异步操作的优缺点及其应用场合

时间:2022-12-18 19:44:47
我曾经提到异步操作能提高系统的吞吐能力,正确使用异步操作来校正滥用异步的错误做法,那异步究竟有何优点值得我们使用?而又有什么缺点需要我们使用的时候小心呢?诚如老赵所说, 异步并不一定能提高系统性能,甚至因为线程的创建,消亡,和切换会增加系统开销,但异步除了提高性能,还可以增强系统的健壮性。在过去,windows程序总是单线程的,在这样的系统中,如果出现了异常,系统就会 因此而崩溃,甚至连我们的操作系统也是单线程的,所以每次出现异常,我们的计算机用户都要不厌其烦强制关机,然后重启才能解决问题。加入多线程之后,当一个线程上的任务发生异常的时候,其他线程有能力不受影响,从此防止整个应用程序的崩溃。此外如果用户是在一个UI中操作某项耗时的操作,如果不使用异步,那UI线程就会被阻塞,导致界面无法响应,用户就会很无助,增加了异步,让复杂的任务在另外的线程中完成,就会有比较好的用户体验。而且异步并不是说对性能提高没有作用,CLR线程的创建,销毁,和线程上下文切换的确会有很大的开销,比如每创建一个线程,都必须申请 1MB的地址空间用于线程的用户模式,申请12KB左右的德地址空间用于线程的内核模式, 而且还要求进程调用每个dll中的一个 固定的函数来通知所有的dll系统创建了一个新的线程,同样在销毁的时候,也要做类似的通知,上面这一切 似乎都说明了异步操作对于性能的坏处,但事实并非完全如此,我们知道当前的处理器基本上都 是双核,或者支持hyper-thread,一个线程的执行总会占用 1 个cpu逻辑核,如果我们的计算机 是 4核,8核,而我们不采用异步,那其实多核就没什么太大优势,因为总是 1个核在工作,而 另外的核却在休息,效率肯定低下,而此时用多线程,就可以充分使用计算机的处理器资源。同 时对于一些有IO限制的操作而言,如读取磁盘文件,网络数据相关操作时,整个过程并不是完 全靠运算,而是要通过磁盘驱动器或者网络驱动器来协助完成,比如读取磁盘中的一个文件,当 应用程序的读取线程发出读请求的时候,该请求会被磁盘驱动器所排队处理,假如它是个很长的 操作,那么该操作会在磁盘驱动器上排队或者执行很长时间,而这段时间读线程就处于阻塞的状 态,这样就浪费了线程资源,正确的做法应该是线程将读请求发送到磁盘驱动器后马上返回,继 续处理其他任务,而当磁盘驱器操作完成的时候,由磁盘驱动器来通知或者由一个线程来轮询 执行状态。这样就防止线程资源被浪费,从而提高系统性能。总结一下上面的说法,

优点:   
1) 在 I/O受限等情况下,异步能提
2) 异步能增强系统健壮性  
3) 异步能改善用户体验   


同时也有缺点,如下   
1) 滥用异步,会影响性能  
2) 增加编程难度   

总结对比各种异步操作的实现方式   
实现异步,主要包含以下几种方法   
1)  使用专用线程,方法为:   
System.Threading.ThreadStart ts = new System.Threading.ThreadStart(void(object state) target);   
System.Threading.Thread th = new System.Threading.Thread(ts);   
ts.Start();   
调用 Start()方法之前,并没有实质性得创建线程资源,而是 Start()后才进行创建,此种方式的好
处在于能设置线程是前台线程还是后台线程,并且能控制线程的挂起和消亡   
  
2)  使用线程池中的线程   
线程是一种比较宝贵的资源,所以使用的时候就要加倍珍惜,线程池中线程在使用完成之后并不
是马上销毁, 而是回到池中等待下一次的使用, 这样就可以较少线程创建的消耗。 使用方法如下:    
ThreadPool.QueueUserWorkItem(WaitCallback callback)   
需要注意的是此种方法使用的均为后台线程    


3)  使用异步编程模型   
这种方法是 MS推荐的使用方法,该模型普遍格式为:   
BeginXXX(…IAsyCallBack callback,object asyState);   
EndXXX(IAsyState ar);   
这种模型的好处上面已经有所阐述


4) 使用 BackgroundWorker   
.Net2.0 下提供了 BackgroundWorker,使用它可以轻易的完成异步操作,并且它还有一些功能
上的加强,比如取消操作、