C#5.0中的异步编程关键字async和await

一、Asynchronous methods 异步方法

.NET 4.5 的推出,对于C#又有了新特性的增加——就是C#5.0中async和await两个关键字,这两个关键字简化了异步编程。

  • 使用async修饰的方法被称为异步方法,这个方法调用时应该在前面加上await。
  • 异步方法命名应该以Async结尾,这样大家知道调用的时候使用await。

async和await关键字只是编译器的功能,编译器最终会用Task类创建代码。

1、创建返回任务的异步方法

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

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

定义一个方法GreetingAsync,可以使方法异步化,其传入的参数不做强制要求。

异步方法,返回类型必须为Task、Task或void。不能作为程序的入口点,即Main方法不能使用async修饰符。

基于任务的异步模式指定,并返回一个任务。

注意,该方法返回的是Task,定义了一个返回字符串的任务,与同步方法返回值一致。

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

2、调用异步方法

可以使用await关键字调用返回任务的异步方法GreetingAsync。

注意:await修饰符只能用于返回Task或者Task的方法。

并且使用await关键字的方法,这里是CallerWithAsync(),必须要用async关键字修饰符声明。

在GreetingAsync方法完成前,被async关键字修饰的方法内await关键字后面的代码不会继续执行。

但是,启动被async关键字修饰的方法的线程可以被重用,而没有被阻塞。

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

3、简单实例

void Main()
{
    DisplayValue();
    System.Diagnostics.Debug.WriteLine("MyClass() End.");
}

public async void DisplayValue()
{
    double result = await GetValueAsync(1234.5, 1.01);//此处会开新线程处理GetValueAsync任务,然后方法马上返回。这之后的所有代码都会被封装成委托,在GetValueAsync任务完成时调用
    System.Diagnostics.Debug.WriteLine("Value is : " + result);
}

public Task<double> GetValueAsync(double num1, double num2)
{
    return Task.Run(() =>
    {
        for (int i = 0; i < 1000000; i++)
        {
            num1 = num1 / num2;
        }
        return num1;
    });
}

上面在MyClass的构造函数里调用了async关键字标记的异步方法DisplayValue(),DisplayValue()方法里执行了一个await关键字标记的异步任务GetValueAsync(),这个异步任务必须是以Task或者Task作为返回值的。

而我们也看到,异步任务执行完成时实际返回的类型是void或者TResult,DisplayValue()方法里await GetValueAsync()之后的所有代码都会在异步任务完成时才会执行。

DisplayValue()方法实际执行的代码如下:

public void DisplayValue()
{
    System.Runtime.CompilerServices.TaskAwaiter<double> awaiter = GetValueAsync(1234.5, 1.01).GetAwaiter();
    awaiter.OnCompleted(() =>
    {
        double result = awaiter.GetResult();
        System.Diagnostics.Debug.WriteLine("Value is : " + result);
    });
}

可以看到,async和await关键字只是把上面的代码变得更简单易懂而已。

程序的输出如下:

MyClass() End.

Value is : 2.47032822920623E-322

4、使用async 和await定义异步方法不会创建新线程, 它运行在现有线程上执行多个任务。

// 使用C# 5.0中提供的async 和await关键字来定义异步方法
// 从代码中可以看出C#5.0 中定义异步方法就像定义同步方法一样简单。
private async Task<long>  AccessWebAsync()
{
    MemoryStream content = new MemoryStream();

    // 对MSDN发起一个Web请求
    HttpWebRequest webRequest = WebRequest.Create("http://msdn.microsoft.com/zh-cn/") as HttpWebRequest;
    if (webRequest != null)
    {
        // 返回回复结果
        using (WebResponse response = await webRequest.GetResponseAsync())
        {
            using (Stream responseStream = response.GetResponseStream())
            {
                await responseStream.CopyToAsync(content);
            }
        }
    }

    txbAsynMethodID.Text = Thread.CurrentThread.ManagedThreadId.ToString();
    return content.Length;
}

运行结果如下:

三、async和await关键字剖析

我们对比下上面使用async和await关键字来实现异步编程的代码和在第二部分的同步代码,有没有发现使用async和await关键字的异步实现和同步代码的实现很像,只是异步实现中多了async和await关键字和调用的方法都多了async后缀而已。

正是因为他们的实现很像,所以我在第四部分才命名为使用async和await使异步编程更简单,就像我们在写同步代码一样,并且代码的coding思路也是和同步代码一样,这样就避免考虑在APM中委托的回调等复杂的问题,以及在EAP中考虑各种事件的定义。

下面再分享下几个关于async和await常问的问题

  • 问题一:是不是写了async关键字的方法就代表该方法是异步方法,不会堵塞线程呢?

答: 不是的,对于只标识async关键字的(指在方法内没有出现await关键字)的方法,调用线程会把该方法当成同步方法一样执行,所以然而会堵塞GUI线程,只有当async和await关键字同时出现,该方法才被转换为异步方法处理。

  • 问题二:“async”关键字会导致调用方法用线程池线程运行吗?

答: 不会,被async关键字标识的方法不会影响方法是同步还是异步运行并完成,而是,它使方法可被分割成多个片段,其中一些片段可能异步运行,这样这个方法可能异步完成。这些片段界限就出现在方法内部显示使用”await”关键字的位置处。所以,如果在标记了”async”的方法中没有显示使用”await”,那么该方法只有一个片段,并且将以同步方式运行并完成。在await关键字出现的前面部分代码和后面部分代码都是同步执行的(即在调用线程上执行的,也就是GUI线程,所以不存在跨线程访问控件的问题),await关键处的代码片段是在线程池线程上执行。总结为——使用async和await关键字实现的异步方法,此时的异步方法被分成了多个代码片段去执行的,而不是像之前的异步编程模型(APM)和EAP那样,使用线程池线程去执行一整个方法。

到此这篇关于C#5.0异步编程之async和await的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C#异步编程Task的创建方式

    一.简介 ThreadPool相比Thread来说具备了很多优势,但是ThreadPool却又存在一些使用上的不方便.比如:Task支持线程的取消.完成.失败通知等交互性操作,但是ThreadPool不支持:Task支持线程执行的先后次序,但是ThreadPool不支持::以往,如果开发者要实现上述功能,需要完成很多额外的工作,现在,FCL中提供了一个功能更强大的概念:Task.Task在线程池的基础上进行了优化,并提供了更多的API.在FCL4.0中,如果我们要编写多线程程序,Task显然已经

  • .NET2.0版本中基于事件的异步编程模式(EAP)

    一.引言 APM为我们实现异步编程提供了一定的支持,同时它也存在着一些明显的问题——不支持对异步操作的取消和没有提供对进度报告的功能,对于有界面的应用程序来说,进度报告和取消操作的支持也是必不可少的. 微软在.NET 2.0的时候就为我们提供了一个新的异步编程模型,也就是基于事件的异步编程模型——EAP(Event-based Asynchronous Pattern ). 二.介绍 实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类

  • .NET1.0版本中的异步编程模型(APM)

    一.概念 .NET 1.0提出了APM(Asynchronous Programming Model)即异步编程模式. .NET的类库有以BeginXXX和EndXXX类似的方法,就是使用异步编程模型. NET Framework很多类也实现了该模式,同时我们也可以自定义类来实现该模式,即在自定义的类中实现返回类型为IAsyncResult接口的BeginXXX方法和EndXXX方法,另外委托类型也定义了BeginInvoke和EndInvoke方法. 异步编程模型的本质 利用委托和线程池帮助我

  • .NET异步编程模式的三种类型介绍

    一.引言 .NET中很多的类.接口在设计的时候都考虑了多线程问题,简化了多线程程序的开发,不用自己去写WaitHandler等这些底层的代码,由于历史的发展,这些类的接口设计有着三种不同的风格:EAP.APM和TPL.目前重点用TPL. 二.EAP EAP是Event-based Asynchronous Pattem(基于事件的异步模型)的简写,类似于Ajax中的XmlHttpRequest,send之后并不是处理完成了,而是在onreadystatechange事件中再通知处理完成.看下面的

  • C#异步编程由浅入深(三)之详解Awaiter

      上一篇末尾提到了Awaiter这个类型,上一篇说了,能await的对象,必须包含GetAwaiter()方法,不清楚的朋友可以看上篇文章.那么,Awaiter到底有什么特别之处呢?  首先,从上篇文章我们知道,一个Awaiter必须实现INotifyCompletion接口,这个接口定义如下: namespace System.Runtime.CompilerServices { /// <summary> /// Represents an operation that will sch

  • C#异步编程由浅入深(二)之Async/Await的使用

      考虑到直接讲实现一个类Task库思维有点跳跃,所以本节主要讲解Async/Await的本质作用(解决了什么问题),以及Async/Await的工作原理.实现一个类Task的库则放在后面讲.首先回顾一下上篇博客的场景. class Program { public static string GetMessage() { return Console.ReadLine(); } public static string TranslateMessage(string msg) return m

  • C#异步编程的三种模式

    使用异步编程,方法调用是在后台运行(通常在线程和任务的帮助下),并且不会阻塞调用线程.异步编程有三种模式:异步模式,基于事件的异步模式和基于任务的异步模式(TAP). 一.异步模式 从.NET 1.0开始 .NET Framework就提供了异步特性,.NET Framework的许多类(但不是全部类)都实现了一个或多个异步模式,自定义类可以通过委托类型实现异步模式..NET Framework的许多类的异步模式定义了BeginXXX()方法和EndXXX方法.如HttpWebRequest类有

  • C#异步编程由浅入深(一)

    目录 一.什么算异步? 二.在编程中的异步 三.原始的异步编程模式之回调函数 1.回调函数 一.什么算异步? 广义来讲,两个工作流能同时进行就算异步,例如,CPU与外设之间的工作流就是异步的.在面向服务的系统中,各个子系统之间通信一般都是异步的,例如,订单系统与支付系统之间的通信是异步的,又如,在现实生活中,你去馆子吃饭,工作流是这样的,点菜->下单->做你的事->上菜->吃饭,这个也是异步的,具体来讲你和厨师之间是异步的,异步是如此重要,因外它代表者高效率(两者或两者以上的工作可

  • .NET实现异步编程async和await

    await和async是.NET Framework4.5框架.C#5.0语法里面出现的,await和async是语法糖. 注意: 1.async出现在方法的声明里面,任何一个方法都可以增加async. 2.await放在Task前面,async和await是成对出现的,只有async是没有意义的,只有await是报错的. 只有async是没有意义的. 只有await是报错的. 3.await 只能放在task前面,不推荐void返回值,使用Task来代替.Task和Task<T>能够使用aw

  • C#异步编程async/await用法详解

    异步函数简介 一般指 async 修饰符声明得.可包含await表达式得方法或匿名函数. 声明方式 异步方法的声明语法与其他方法完全一样, 只是需要包含 async 关键字.async可以出现在返回值之前的任何位置, 如下示例: async public static void GetInfoAsync() { //... } public async static void GetInfoAsync() { //... } public static async void GetInfoAsy

随机推荐