c# 基于任务的异步编程模式(TAP)
异步编程是C#5.0的一个重要改进,提供两个关键字:async和await。使用异步编程,方法的调用是在后台运行(通常在线程或任务的帮助下),但不会阻塞调用线程。异步模式分为3种:异步模式、基于事件的异步模式和基于任务的异步模式(TAP)。TAP是利用关键字async和await实现的,本文将讲解TAP模式。async和await关键字只是编译器的功能。编译器最终会用Task类创建代码。
1、创建任务
建立一个同步方法Greeting,该方法在等待一段时间后,返回一个字符串。
privatestringGreeting(intdelay,stringname) { System.Threading.Thread.Sleep(delay); returnstring.Format("Hello,{0}.",name); }
定义一个方法GreetingAsync,可以使方法异步化,其传入的参数不做强制要求。基于任务的异步模式指定,并返回一个任务。注意,该方法返回的是Task
privateTaskGreetingAsync(stringname,intdelay=3000) { returnTask.Run (()=> { returnGreeting(delay,name); }); }
2、调用异步方法
可以使用await关键字调用返回任务的异步方法GreetingAsync。但是,使用await关键字的方法必须要用async关键字修饰符声明。在GreetingAsync方法完成前,被async关键字修饰的方法内await关键字后面的代码不会继续执行。但是,启动被async关键字修饰的方法的线程可以被重用,而没有被阻塞。
publicasyncvoidCallerWithAsync() { stringresult=awaitGreetingAsync("Nigel",2000); Console.WriteLine(result); }
注意:async修饰符修饰只能用于返回Task或void的方法。不能作为程序的入口点,即Main方法不能使用async修饰符。await修饰符只能用于返回Task的方法。
3、延续任务
GreetingAsync方法返回一个Task
publicvoidCallsWithContinuationTask() { Tasktask=GreetingAsync("Stephanie",1000); task.ContinueWith(t=> { Console.WriteLine(t.Result); }); }
实际上,编译器会把await关键字后的所有代码放进ContinueWith方法内。不论是await关键字的方法还是任务的ContinueWith方法,在方法的不同生命阶段使用了不同的线程。都是当await关键字的方法或任务执行完毕后,再由另一个线程去执行await关键字后面的代码,或给当前线程添加新的任务去执行相关代码。
在具有UI的应用程序中,应用程序的窗体的控件不允许跨线程访问,需要使用控件的InvokeRequired属性和Invoke方法,将访问UI的方法代码块以委托的形式传递给控件的Invoke,但是在执行前需要判断控件的InvokeRequired。在使用async和await关键字,当await完成后,不需要做任何处理,就可以放访问UI线程(实际上是将控制权又交给了UI线程)。
4、使用多个异步方法
4.1、按顺序调用多个异步方法
使用await关键字可以调用每个异步方法。如果一个异步方法依赖于另一个异步方法,将会起到很大作用。但当异步方法之间没有相互依赖的时候,不使用await关键字将更快返回结果。
publicasyncvoidMultipleAsyncMethods() { DateTimestart=DateTime.Now; stringresult1=awaitGreetingAsync("Jack",2500);//先执行完它 stringresult2=awaitGreetingAsync("Tim",1500);//再执行它 //输出结果 Console.WriteLine("Finishedbothmethods:MultipleAsyncMethods.\nResult1:{0},Result2:{1}",result1,result2); Console.WriteLine("Usetime:{0}",(DateTime.Now-start).TotalMilliseconds); }
4.2、使用组合器
如果任务之间并不依赖于另一个任务,每个异步方法都不需要使用await,而是把每个异步方法的返回结果赋值给Task变量,使用组合器让这些任务并行运行。当组合器内的所有任务都完成后,才会执行后面的代码。
publicasyncvoidMultipleAsyncMethodsWithCombinators1() { DateTimestart=DateTime.Now; Taskt1=GreetingAsync("Jack",2500); Task t2=GreetingAsync("Tim",1500); awaitTask.WhenAll(t1,t2); //输出结果 Console.WriteLine("Finishedbothmethods:MultipleAsyncMethodsWithCombinators1.\nResult1:{0},Result2:{1}",t1.Result,t2.Result); Console.WriteLine("Usetime:{0}",(DateTime.Now-start).TotalMilliseconds); }
如果所有任务类型都返回相同的类型,则可用该类型的数组作为await返回的结果
publicasyncvoidMultipleAsyncMethodsWithCombinators2() { DateTimestart=DateTime.Now; Taskt1=GreetingAsync("Jack",2500); Task t2=GreetingAsync("Tim",1500); string[]results=awaitTask.WhenAll(t1,t2); //输出结果 Console.WriteLine("Finishedbothmethods:MultipleAsyncMethodsWithCombinators2.\nResult1:{0},Result2:{1}",results[0],results[1]); Console.WriteLine("Usetime:{0}",(DateTime.Now-start).TotalMilliseconds); }
5、异步方法的异常处理
如果调用异步方法,但是没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常。因为在异步方法执行出现异常之前,已经执行完毕。
如何捕获异常见《基于任务的异步编程模式(TAP)的错误处理》。
以上就是c#基于任务的异步编程模式(TAP)的详细内容,更多关于c#异步编程的资料请关注毛票票其它相关文章!