接上文 多线程编程学习笔记——任务并行库(一)html
接上文 多线程编程学习笔记——任务并行库(二)编程
接上文 多线程编程学习笔记——任务并行库(三)c#
接上文 多线程编程学习笔记——任务并行库(四)多线程
经过前面的文章,已经学习了怎么使用线程,怎么使用线程同步,怎么使用线程池,怎么使用任务并行库。尽管经过上面的学习,对于线程的使用愈来愈简单。有没有更简单的方法呢。asp.net
C# 5.0以后,微软在c#语言中添加了两个关键字async与await,这是在TPL上面的更高一级的抽象,真正简化了异步编程的编程方式,从而有助于咱们编写出真正健壮少bug的异步应用程序。下面我先来看一个最简单的示例。异步
async Task<string> AsyncHello() { await Task.Delay(TimeSpan.FromSeconds(2)); Return “ Hello world”; }
使用async标记异步函数,建议返回async Task<T>。async
Await只能使用在有async标志的方法内部。在async标记的方法内部最少要有一个await,固然,若是一个也没有,编译也不会报错,可是会有编译警告。以下图。异步编程
上面的代码在执行完await调用的代码之行后该方法会直接返回。若是同步执行,执行线程会阻塞2秒以后返回结果,本示例里在执行完await操做后,当即将工做线程放回线程池中,咱们会异步等待。2秒后,咱们会从线程池中取得工做线程并继续运行其中剩余的异步方法。这就容许咱们在等待的2秒的时间里能够重用线程池中的线程,这对提升应用程序的可伸缩性很是重要。经过使用async与await咱们拥有了线性的程序控制流程,可是执行过程倒是异步的。函数
1、 使用await获取异步操做结果post
本示例是学习await如何获取异步操做结果。同时会与TPL进行比较。
1.示例代码以下。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace ThreadAsyncDemo { class Program { static void Main(string[] args) { Task t = AsyncWithTPL(); t.Wait(); t = AsyncWithAwait(); t.Wait(); Console.Read(); } static Task AsyncWithTPL() { Task<string> task1 = GetInfoAsync("Task 1"); Task task2 = task1.ContinueWith(task => Console.WriteLine(task1.Result), TaskContinuationOptions.NotOnFaulted); Task task3 = task1.ContinueWith(task => Console.WriteLine(task1.Exception.InnerException), TaskContinuationOptions.OnlyOnFaulted); return Task.WhenAny(task2, task1); } async static Task AsyncWithAwait() { try { string result = await GetInfoAsync("Task 4"); Console.WriteLine(result); } catch (Exception ex) { Console.WriteLine(ex.Message); } } async static Task<string> GetInfoAsync(string name) { await Task.Delay(TimeSpan.FromSeconds(2)); //throw new Exception("抛出异常信息!"); return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工做线程是不是线程池中的线程:{2}", name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); } } }
2.程序运行的结果以下图。
程序同时运行了两个异步操做。其中一个是标准的TPL代码,另外一个使用了async与await两个关键字。AsyncWithTPL启动了一个任务,运行两秒以后返回关于工做线程信息的字符串。而后咱们定义了一个后续操做,用于在异步操做完成后打印出操做结果,还有另外一个后续操做,用于万一有错误时,打印出异常信息。最终返回了一个表明其中一个后续操做任务的任务,并等等其在主函数中完成。
在asyncWithAwait方法中,咱们对任务使用await并获得了相同 的结果。这和编写普通的同步代码的风格同样,即咱们获取了任务的结果,打印了出来,若是任务完成时带有错误则捕获异常。关键不一样的是这其实是一个异步操做。使用await后,c#当即建立了一个任务,其中一个有后续操做任务,包含了await操做符后面的全部剩余代码。这个新任务也处理了异常。而后这个任务返回 到主方法并等待共完成 。
所以能够看出程序中的两段代码在概念上是相同的,使用await由编译 器隐式地处理了异步代码。
3. 咱们把上面注释的抛出异常的代码,取消注释,而后运行程序。获得以下图的结果。
注:在gui与asp.net之类的环境 中不推荐 使用task.wait和taskResult方法同,由于若是代码写的很差,很容易致使死锁。
2、 在Lambda表达式中使用await操做符
本示例学习如何在lambda表达式中使用await。将学习如何编写一个使用了await的匿名方法,而且获取异步执行该方法的结果。
1.示例代码以下。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Threading; namespace ThreadAsyncDemo { class Program { static void Main(string[] args) { Task t = AsyncProcess(); t.Wait(); Console.Read(); } async static Task AsyncProcess() { Func<String, Task<string>> asyncLambda = async name => { await Task.Delay(TimeSpan.FromSeconds(2)); return string.Format(" Task {0} 正在运行在线程 ID={1}上。这个工做线程是线程池的线程:{2}" ,name,
Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread); }; string result = await asyncLambda("async lambda"); Console.WriteLine(result); } } }
2.程序运行结果,以下图。
首先不能在main方法中使用async,咱们将异步函数移到了asyncProcess中,而后使用async关键字声明了一个lambda表达式。因为 任何lambda表达式的类型都不能经过lambda自身来推断,因此不得不显示地指定类型为一字符串,并返回一个Task<string>对象 。
而后,咱们定义 了lambda表达式体,这个方法虽然定义返回的是一个Task<string>对象 ,但实际上返回的是字符串,却没有编译错误。这是由于c#编译器自动 产生了一个任务并返回给咱们。
最后一步就是打印出lambda 表达式执行后的结果。