异步编程是受公共语言运行库的许多领域(如远程处理、ASP.NET 和 Windows 窗体)支持的功能。异步编程是 .NET Framework 中的核心概念。使用 .NET 异步编程,在程序继续执行的同时对 .NET 类方法进行调用,直到进行指定的回调为止;或者如果没有提供回调,则直到对调用的阻塞、轮询或等待完成为止。
异步编程是由 .NET Framework 的许多区域支持的功能,这些区域包括:
文件 IO、流 IO、套接字 IO
网络:HTTP、TCP
远程处理信道(HTTP、TCP)和代理
使用 ASP.NET 创建的 XML Web services
ASP.NET Web 窗体
使用 MessageQueue 类的消息队列
异步委托
.NET Framework 允许异步调用任何方法。定义与需要调用的方法具有相同签名的委托;公共语言运行库将自动为该委托定义具有适当签名的 BeginInvoke 和 EndInvoke 方法。
BeginInvoke 方法用于启动异步调用。它与需要异步执行的方法具有相同的参数,只不过还有两个额外的参数(将在稍后描述)。BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。
EndInvoke 方法用于检索异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。EndInvoke 的参数包括需要异步执行的方法的 out 和 ref 参数以及由 BeginInvoke 返回的 IAsyncResult。
调用了 BeginInvoke 后,可以:
进行某些操作,然后调用 EndInvoke 一直阻塞到调用完成。
使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke。
轮询由 BeginInvoke 返回的 IAsyncResult,确定异步调用何时完成,然后调用 EndInvoke。
将用于回调方法的委托传递给 BeginInvoke。该方法在异步调用完成后在 ThreadPool 线程上执行,它可以调用 EndInvoke。
下面是一个使用委托调用异步方法的例子。实例中首先定义了一个AddDelegate类型委托add,并将方法Add绑定到委托实例上。然后定义了IAsyncResult接口类型实例iAR并调用委托add的BeginInvoke方法用于启动异步调用。由于异步调用完成时会发出 WaitHandle 信号,因此可以通过iAR.AsyncWaitHandle.WaitOne();来等待它,在这期间主程序可以执行一些其他的任务以达到程序异步执行的效果。最后调用EndInvoke 方法用于检索异步调用结果。值得注意的是如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。
using System;
using System.Threading;
//使用委托调用异步方法的例子
namespace DelegateCallAsynchronousMethods
...{
class AsyncDelegatesBlocked
...{
public static int Add(int op1, int op2, out int result)
...{
Thread.Sleep(3000); // Simulating work
return (result = op1 + op2);
}
public delegate int AddDelegate(int op1, int op2,
out int result);//声明AddDelegate委托
static void Main()
...{
int result;
/**//*定义一个AddDelegate类型委托add,将方法Add绑定到委托实例上*/
AddDelegate add = new AddDelegate(Add);
Console.WriteLine("[Main] Invoking the asynchronous " +
"Add method");
/**//*BeginInvoke 方法用于启动异步调用。它与您需要异步执行的方法具有相同的参数,还有两个额外的参数
*BeginInvoke 立即返回,不等待异步调用完成。BeginInvoke 返回 IasyncResult,可用于监视调用进度。*/
//定义IAsyncResult接口类型实例iAR
//6, 42, out result为异步执行的方法的参数列表
IAsyncResult iAR = add.BeginInvoke(6, 42, out result,
null, null);
// Here we're simulating doing some work before
// blocking on the Add method's completion.
Console.Write("[Main] Doing other work");
for (int i = 0; i < 10; i++)
...{
Thread.Sleep(200);
Console.Write(".");
}
Console.WriteLine(" [Main] Waiting for Add to finish");
/**//*使用 IAsyncResult.AsyncWaitHandle 获取 WaitHandle,
* 使用它的 WaitOne 方法将执行一直阻塞到发出 WaitHandle 信号,然后调用 EndInvoke。
* 注意:异步调用完成时会发出 WaitHandle 信号,可以通过WaitOne 来等待它*/
iAR.AsyncWaitHandle.WaitOne();
Console.WriteLine("[Main] Add finished, cleaning up");
/**//*EndInvoke 方法用于检索异步调用结果。调用 BeginInvoke 后可随时调用 EndInvoke 方法;
* 如果异步调用未完成,EndInvoke 将一直阻塞到异步调用完成。
* EndInvoke 的参数包括所需要异步执行的方法的 out 和 ref 参数以及由 BeginInvoke 返回的 IAsyncResult。*/
add.EndInvoke(out result, iAR);
Console.WriteLine("[Main] The result is {0}", result);
Console.ReadLine();
}
};
}