在C#程序中,如果使有连接网络等耗费时间的操作,为了让整个程序不必完全停下来等待,可以继续执行其它操作,就要依赖于异步编程。在VS2012之前,异步编程要靠手动实现多线程操作;从VS2012开始,引入了 Await
和 Async
关键字,封装了线程操作,使得异步编程变得简单。
异步方法
异步编程要靠异步方法来实现。使用 async
修饰的方法就是异步方法,必须是 void
,或返回 Task
(Task<T>
)类型的变量。
异步方法调用中的控制流
分为下面几种情况:
- 如果是 void 的异步方法,在自己开始执行的时候就会交回程序的控制权,让外层程序得以继续执行;
- 如果是返回 Task 或者 Task<T> 类型变量的异步方法,返回 Task(Task<T>) 作为结果的同时会启动它,同时交回程序的控制权。
对于返回 Task<T> 的异步方法,由于它承诺了 Task 会返回 T 类型的结果,所以外层代码多半是需要得到这个结果,所以还是得挂起来等待。当然,可以先取回 Task 让它启动,在必要的地方再等待它的结果,例如:
...
Task<string> getStringTask = client.GetStringAsync("http://msdn.microsoft.com"); // 创建task让它先执行
DoIndependentWork(); // 去做其它的事情
string urlContents = await getStringTask; // 需要task的结果了,挂起来等一下
...
对于上边所说“外层方法挂起等待结果”,一般有两种方式,下面分别举例说明。
- 方法1,使用
await
关键字。
public async void TestAsync()
{
var task1 = GetResultAsync("test string");
var result1 = await task1;
}
- 方法2,使用
Task
的Awaiter
。
public void TestAsync1()
{
var result = GetResultAsync("test string").GetAwaiter().GetResult();
}