目录
1 异步编程的必要性
.NET 的异步编程技术主要分为两大块:“使用 IAsyncResult 的异步编程模式” 和 “基于事件的异步编程模式”
1.1 同步调用与异步调用
通常情况下,当我们调用方法 A 后,在 A 返回之前,调用线程得不到程序执行的控制权,也就是说,方法 A 后面的代码是不可能执行的,直到 A 返回为止,这种调用方式称之为 “同步调用”;相反,如果调用在返回之前,调用线程依旧保留控制权,能够继续执行后面的代码,那么称这种调用方式为 “异步调用”,如下图所示。
如上图所示,左边为同步调用,调用线程被阻塞,右边为异步调用,调用线程没有被阻塞。
异步调用的优点
很明显,异步调用不会阻塞调用线程,单位时间内可以处理更多的任务。在 Winform 中异步调用的作用尤其明显。如果我们在 UI 线程中同步调用一个耗时方法,那么窗体界面会出现反应迟钝、卡以及不刷新等现象,主要原因就是同步调用的方法阻塞了 UI 线程,Windows消息不能及时被处理。
异步调用过程中,方法的执行不在调用线程中。也就是说,真正执行任务的线程不再是当前调用线程,那么就会有以下几个问题:
(1)当前调用线程如何知道任务什么时候执行结束,任务执行的结果如何?
(2)当前调用线程怎样给执行任务的线程提供一些额外的参数?
(3)当前调用线程怎样捕获执行任务时可能抛出的异常?
1.2 基于委托的异步调用
委托的一个作用就是可以异步调用与它关联的方法,我们即可以选择同步调用一个委托,也可以选择异步调用一个委托。理论上讲,任何一个方法,通过委托包装后,都可以实现异步调用。
1.2.1 委托的 BeginInvoke 与 EndInvoke 方法
.NET 编译器为我们定义的每个委托类型自动生成了两个方法:BeginInvoke 和 EndInvoke,这两个方法专门用来负责异步调用委托。
BeginInvoke 方法签名如下:
public IAsyncResult BeginInvoke(<输入和输出变量>,AsyncCallback callback,object asyncState);
第一个参数 是定义委托时确定的方法签名中的参数列表;
第二个参数 callback 是当异步调用结束时自动回调的方法;
public delegate void AsyncCallback(IAsyncResult ar);
第三个参数 asyncState 用于向第二个参数所确定的 callback 回调方法提供参数;
BeginInvoke 方法返回一个 IAsyncResult 接口类型:
public interface IAsyncResult
{
object AsyncState { get; }
WaitHandle AsyncWaitHandle { get; }
// 判断异步操作是否同步完成
bool CompletedSynchronously { get; }
// 判断异步操作是否已完成
bool IsCompleted { get; }
}
EndInvoke 方法签名如下:
public <方法返回值类型> EndInvoke(IAsyncResult result);
借助于 IAsyncResult 对象,EndInvoke 方法不断查询异步调用的方法是否执行完毕。当EndInvoke 方法发现异步调用完成时,它取出此异步调用方法执行的结果作为其返回值。这样,启动