C# 异步处理

计算机中有些处理比较耗时。调用这种处理代码时,调用方若是站在那里苦苦等待,会严重影响程序性能。例如,某个程序启动后若是须要打开文件读出其中的数 据,再根据这些数据进行一系列初始化处理,程序主窗口将迟迟不能显示,让用户感到这个程序怎么等半天也不出来,太差劲了。借助异步调用能够把问题轻松化 解:把整个初始化处理放进一个单独线程,主线程启动此线程后接着往下走,让主窗口瞬间显示出来。等用户盯着窗口犯呆时,初始化处理就在背后悄悄完成了。程 序开始稳定运行之后,还能够继续使用这种技巧改善人机交互的瞬时反应。用户点击鼠标时,所激发的操做若是较费时,再点击鼠标将不会当即反应,整个程序显得 很沉重。借助异步调用处理费时的操做,让主线程随时恭候下一条消息,用户点击鼠标时感到轻松快捷,确定会对软件产生好感。编程

      异步调用用来处理从外部输入的数据特别有效。假如计算机须要从一台低速设备索取数据,而后是一段冗长的数据处理过程,采用同步调用显然很不合算:计算机先 向外部设备发出请求,而后等待数据输入;而外部设备向计算机发送数据后,也要等待计算机完成数据处理后再发出下一条数据请求。双方都有一段等待期,拉长了 整个处理过程。其实,计算机能够在处理数据以前先发出下一条数据请求,而后当即去处理数据。若是数据处理比数据采集快,要等待的只有计算机,外部设备能够 连续不停地采集数据。若是计算机同时链接多台输入设备,能够轮流向各台设备发出数据请求,并随时处理每台设备发来的数据,整个系统能够保持连续高速运转。 编程的关键是把数据索取代码和数据处理代码分别归属两个不一样的线程。数据处理代码调用一个数据请求异步函数,而后径自处理手头的数据。待下一组数据到来 后,数据处理线程将收到通知,结束 wait 状态,发出下一条数据请求,而后继续处理数据。windows

 

      异步调用时,调用方不等被调方返回结果就转身离去,所以必须有一种机制让被调方有告终果时能通知调用方。在同一进程中有不少手段能够利用,笔者经常使用的手段是回调、event 对象和消息。安全

 

      回调方式很简单:调用异步函数时在参数中放入一个函数地址,异步函数保存此地址,待有告终果后回调此函数即可以向调用方发出通知。若是把异步函数包装进一个对象中,能够用事件取代回调函数地址,经过事件处理例程向调用方发通知。多线程

 

      event 是 windows 系统提供的一个经常使用同步对象,以在异步处理中对齐不一样线程之间的步点。若是调用方暂时无事可作,能够调用 wait 函数等在那里,此时 event 处于 nonsignaled 状态。当被调方出来结果以后,把 event 对象置于 signaled 状态,wait 函数便自动结束等待,使调用方从新动做起来,从被调方取出处理结果。这种方式比回调方式要复杂一些,速度也相对较慢,但有很大的灵活性,能够搞出不少花样 以适应比较复杂的处理系统。app

 

      借助 windows 消息发通知是个不错的选择,既简单又安全。程序中定义一个用户消息,并由调用方准备好消息处理例程。被调方出来结果以后当即向调用方发送此消息,并经过 wparam 和 lparam 这两个参数传送结果。消息老是与窗口 handle 关联,所以调用方必须借助一个窗口才能接收消息,这是其不方便之处。另外,经过消息联络会影响速度,须要高速处理时回调方式更有优点。异步

 

      若是调用方和被调方分属两个不一样的进程,因为内存空间的隔阂,通常是采用 windows 消息发通知比较简单可靠,被调方能够借助消息自己向调用方传送数据。event 对象也能够经过名称在不一样进程间共享,但只能发通知,自己没法传送数据,须要借助 windows 消息和 filemapping 等内存共享手段或借助 mailslot 和 pipe 等通讯手段。函数

 

      异步调用原理并不复杂,但实际使用时容易出莫名其妙的问题,特别是不一样线程共享代码或共享数据时容易出问题,编程时须要时时注意是否存在这样的共享,并通 过各类状态标志避免冲突。windows 系统提供的 mutex 对象用在这里特别方便。mutex 同一时刻只能有一个管辖者。一个线程放弃管辖权后,另外一线程才能接管。当某线程执行到敏感区以前先接管 mutex,使其余线程被 wait 函数堵在身后;脱离敏感区以后当即放弃管辖权,使 wait 函数结束等待,另外一个线程便有机会光临此敏感区。这样就能够有效避免多个线程进入同一敏感区。性能

 

      因为异步调用容易出问题,要设计一个安全高效的编程方案须要比较多的设计经验,因此最好不要滥用异步调用。同步调用毕竟让人更舒服些:无论程序走到哪里, 只要死盯着移动点就能心中有数,不至于象异步调用那样,总有一种四面受敌、惶惶不安的感受。必要时甚至能够把异步函数转换为同步函数。方法很简单:调用异 步函数后立刻调用 wait 函数等在那里,待异步函数返回结果后再继续往下走。this

C#提供了异步方法调用的功能,先建立一个委托,该委托的签名要与须要异步执行的方法定义相匹配。仍是以代码来讲明。url

委托的声明:

public delegate string AsyncDelegateGetPage( Uri uri , out string url );

调用方代码:

AsyncCallback callback = new AsyncCallback( ProcessPage ); //回调函数声明
AsyncDelegateGetPage ad = new AsyncDelegateGetPage( GetPageSource );//实例化委托类型
IAsyncResult ar = ad.BeginInvoke( this.ObtainWork() ,out url, callback , ad );//开始调用
ar.AsyncWaitHandle.WaitOne();//阻塞主线程,直到异步完成,用于多线程同步,通常能够不须要。

BeginInvoke方法为开始异步调用,其参数为动态的,依据委托的签名。上面的状况,参数为:Uri , out url,回调函数实例(可为null),委托实例(可为null)。即前面的几个参数为委托方法的参数,后面2个分别是回调函数实例和委托实例。参数委托 实例用于将该实例传递到回调函数中。注意回调函数的必须为void ,而且参数为IAsyncResult 类型。

委托的方法代码:

public String GetPageSource( Uri uri , out string url ){
    url = uri.ToString();
    return this.GetPageSource( uri );
}

回调函数代码:

void ProcessPage( IAsyncResult ar ){
    AsyncDelegateGetPage andl = (AsyncDelegateGetPage)ar.AsyncState;
    string url;
    string source = andl.EndInvoke( out url, ar );
}

委托类型的EndInvoke方法,参数为异步结果,IAsyncResult类型。执行该方法后,返回异步调用的结果。

以上是针对有回调函数的状况。

原文:http://blog.csdn.net/Come_On_steven/article/details/4332249

相关文章
相关标签/搜索