基于任务的异步编程模式(TAP) 基于任务的异步编程模式(TAP)的错误处理

异步编程是C#5.0的一个重要改进,提供两个关键字:async和await。使用异步编程,方法的调用是在后台运行(一般在线程或任务的帮助下),但不会阻塞调用线程。异步模式分为3种:异步模式、基于事件的异步模式和基于任务的异步模式(TAP)。TAP是利用关键字async和await实现的,本文将讲解TAP模式。async和await关键字只是编译器的功能。编译器最终会用Task类建立代码。html

一、建立任务

创建一个同步方法Greeting,该方法在等待一段时间后,返回一个字符串。编程

 private string Greeting(int delay, string name)
 {
     System.Threading.Thread.Sleep(delay);
     return string.Format("Hello, {0}.", name);
 }

定义一个方法GreetingAsync,能够使方法异步化,其传入的参数不作强制要求。基于任务的异步模式指定,并返回一个任务。注意,该方法返回的是Task<string>,定义了一个返回字符串的任务,与同步方法返回值一致。数组

private Task<string> GreetingAsync(string name, int delay = 3000)
{
    return Task.Run<string>(() =>
    {
        return Greeting(delay, name);
    });
}

二、调用异步方法

能够使用await关键字调用返回任务的异步方法GreetingAsync。可是,使用await关键字的方法必需要用async关键字修饰符声明。在GreetingAsync方法完成前,被async关键字修饰的方法内await关键字后面的代码不会继续执行。可是,启动被async关键字修饰的方法的线程能够被重用,而没有被阻塞。异步

public async void CallerWithAsync()
{
    string result = await GreetingAsync("Nigel", 2000);
    Console.WriteLine(result);
}

 注意:async修饰符修饰只能用于返回Task或void的方法。不能做为程序的入口点,即Main方法不能使用async修饰符。await修饰符只能用于返回Task的方法。

三、延续任务

GreetingAsync方法返回一个Task<string>对象。该对象包含任务建立的信息,并保存到任务完成。Task类的ContinueWith方法可在任务完成后继续调用的代码。async

 public void CallsWithContinuationTask()
 {
     Task<string> task = 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线程)。post

四、使用多个异步方法

4.一、按顺序调用多个异步方法

使用await关键字能够调用每一个异步方法。若是一个异步方法依赖于另外一个异步方法,将会起到很大做用。但当异步方法之间没有相互依赖的时候,不使用await关键字将更快返回结果。ui

 public async void MultipleAsyncMethods()
 {
     DateTime start = DateTime.Now;
     string result1 = await GreetingAsync("Jack",2500);//先执行完它
     string result2 = await GreetingAsync("Tim",1500);//再执行它
     //输出结果
     Console.WriteLine("Finished both methods: MultipleAsyncMethods.\nResult 1: {0}, Result 2: {1}", result1, result2);
     Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
 }

4.二、使用组合器

若是任务之间并不依赖于另外一个任务,每一个异步方法都不须要使用await,而是把每一个异步方法的返回结果赋值给Task变量,使用组合器让这些任务并行运行。当组合器内的全部任务都完成后,才会执行后面的代码。url

public async void MultipleAsyncMethodsWithCombinators1()
{
    DateTime start = DateTime.Now;
    Task<string> t1=  GreetingAsync("Jack", 2500);
    Task<string> t2= GreetingAsync("Tim", 1500);
    await Task.WhenAll(t1, t2);
    //输出结果
    Console.WriteLine("Finished both methods: MultipleAsyncMethodsWithCombinators1.\nResult 1: {0}, Result 2: {1}", t1.Result, t2.Result);
    Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
}

若是全部任务类型都返回相同的类型,则可用该类型的数组做为await返回的结果spa

public async void MultipleAsyncMethodsWithCombinators2()
{
    DateTime start = DateTime.Now;
    Task<string> t1 = GreetingAsync("Jack", 2500);
    Task<string> t2 = GreetingAsync("Tim", 1500);
    string[] results= await Task.WhenAll(t1, t2);
    //输出结果
    Console.WriteLine("Finished both methods: MultipleAsyncMethodsWithCombinators2.\nResult 1: {0}, Result 2: {1}", results[0], results[1]);
    Console.WriteLine("Use time: {0}", (DateTime.Now - start).TotalMilliseconds);
}

 五、异步方法的异常处理

若是调用异步方法,可是没有等待,那么调用异步方法的线程中使用传统的try/catch块是不能捕获到异步方法中的异常。由于在异步方法执行出现异常以前,已经执行完毕。

如何捕获异常见《基于任务的异步编程模式(TAP)的错误处理》。

相关文章
相关标签/搜索