使用异步编程,方法调用时在后台运行,并且不会阻塞调用线程。
异步编程模型Async Patterns Model(APM)
异步模式定义了BeginXXX和EndXXX方法。BeginXXX方法接受其同步方法的所有输入参数,EndXXX方法使用同步方法的所有输出参数,并按照同步方法的返回类型来返回结果。
//异步模式定义了BeginXXX和EndXXX方法
WebRequest request = WebRequest.Create("http://www.baidu.com");
var result = request.BeginGetResponse((obj) => {
}, null);
var resp = request.EndGetResponse(result);
基于事件的异步模式Event-based Async Pattern(EAP)
基于事件的异步模式定义了一个带有“Async”后缀的方法。例如,对于同步方法DownloadString,WebClient提供了异步方法DownloadStringAsync。并且你需要编写DownloadStringCompleted事件,这个事件会在异步方法完成后调用。
基于事件的异步方法优势在于易于使用。但是,在自定义类中这个模式就没有这么简单了。
//基于事件的异步模式定义了一个带有“Async”后缀的方法
var client = new WebClient();
client.Encoding = Encoding.UTF8;
client.DownloadStringCompleted += (sender1, e1) =>
{
var resp = e1.Result;
};
client.DownloadStringAsync(new Uri("http://www.baidu.com"));
基于任务的异步模式Task-based Async Pattern(TAP)
该模式定义一个带有“Async”后缀的方法,并返回一个Task类型。例如WebClient提供的基于任务的异步方法DownloadStringTaskAsync,该方法返回一个Task<string>,可以用string类接收它,并使用await关键字,await关键字会解除线程(UI线程)的阻塞,完成其他任务。
//基于任务的异步模式
var client = new WebClient();
client.Encoding = Encoding.UTF8;
string resp = await client.DownloadStringTaskAsync("http://www.baidu.com");
async和await关键字只是编译器的功能。编译器会用Task类创建代码。如果不使用者两个关键字,也可以用C# 4.0和Task类的方法来实现同样的功能,只是没有那么方便。
async修饰符只能用于返回.NET类型的Task或void方法,以及Window运行库的IAsyncOperation。
Task类的ContinueWith方法定义了任务完成后就调用的代码。指派给ContinueWith方法的委托接收已完成的任务作为参数传入,使用Result属性可以访问任务返回的结果。
public string Greeting(string name)
{
//同步任务
Task.Delay(2000).Wait();//等同于Thread.Sleep()
return "hello " + name;
}
public Task<string> GreetingAsync(string name)
{
//异步任务
return Task.Run<string>(() => {
return Greeting(name);
});
}
//延续任务
Task<string> task = GreetingAsync("Xie");
task.ContinueWith(t => {
var msg = t.Result + " !";
MessageBox.Show(msg);
});
Task类定义了WhenAll和WhenAny组合器。从WhenAll方法返回的Task,是在所有传入方法的任务都完成了才会返回Task。从WhenAny方法返回的Task,是在其中一个传入方法完成了就会返回Task。
Task<string> task = GreetingAsync("Wang");//耗时2秒
Task<string> task2 = GreetingAsync2("Bai");//耗时6秒
//其中一个线程执行完毕就会继续执行
//var task3 = await Task.WhenAny(task, task2);
//MessageBox.Show(task3.Result);
//当所有线程执行完才会继续执行
var task3 = await Task.WhenAll(task, task2);
MessageBox.Show(task3[0] + "," + task3[1]);
想了解更多关于C# 6与.NET Core的知识请参考:《C#高级编程》