await-async

异步调用对于程序员而言是一个十分重要的概念,通过它可以实现方法的调用者和被调用者的并发执行(也即是处于不同的线程中执行)。但是它的实现并不容易,需要进行比较复杂的构造。但是.Net引入了await-async关键字,将异步调用的构造变得十分简单。为了更清楚的表述,本文以C#作为编程语言,写了一个例子

1.async和await
await是一个运算符,是.Net为简化异步调用的程序编写引入的。它的作用是发起一个任务(Task/Task<TResult>),换句话说await的操作对象是Task/Task<TResult>对象。如以下的例子:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;

namespace Test_Await
{
    public class Program
    {
        public string str;
        public async Task TestAwait()
        {
            try
            {
                using (HttpClient client = new HttpClient())
                {
                    string str = await client.GetStringAsync("http://www.baidu.com");
                    System.Console.WriteLine(str);
                }
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e.Message);
            }
        }

        public async void Test()
        {
            await TestAwait();
            System.Console.WriteLine(str);
        }

        static void Main(string[] args)
        {
            Program obj = new Program();
            obj.Test();
            Thread.Sleep(1000);
       }
    }
}


这个例子很简单,就是下载百度主页的html文档。通过以上的例子,可以大概看出的await和async的编程规则。使用async和await关键字需要注意几点:
  • 由async关键字修饰的方法,返回值有三种,void/Task/Task<TResult>(任务模板类),如上例中的Test()和TestAwait()方法;
  • 由async修饰的方法,内部至少要有一个await表达式,否则编译器会报警告,并最终将方法按照同步的方式执行;
  • 由async修饰的方法,如果返回值为void,则不能使用await运算符,因为前面已经说过了await的操作对象为Task/Task<TResult>实例
  • await表达式只能出现在由async修饰的方法中,因此主函数不能出现await表达式。
2. 原理
async和await关键字,不会创建新的线程;创建新的线程,可以通过Task.Run实现;由async修饰的方法中,如果有await表达式,执行该表达式发起一个新任务时,程序直接将CPU控制权返还给方法的调用者,任务结束后,会继续执行await表示式后面的内容;如果没有await表达式,则当做同步调用处理了。也就是说在含有await表达式的方法中,await表达式会让方法的执行“挂起”,只有等任务完成后才会继续往下执行。
async和await内部实现机制:编译器将await表达式后面的语句从方法中拆分出来,附加到任务结尾。任务结束后,就可以继续调用拆分出来的部分了。这样,一个比较有意思的现象是,如果任务是在另一个线程中执行的,则await表达式的前后部分代码并不是处在一个线程中,后部分的代码是在任务所在线程中执行的,这也就是为什么主线程中需要添加Thread.Sleep()语句了。如果不这样的话,主线程执行了
<pre name="code" class="csharp">string str = await client.GetStringAsync("http://www.baidu.com");
 语句之后立马退出了,这样子线程也会随之撤销,从而导致任务没法继续进行了。 
以上例进行说明:
主线程在执行await TestAwait()语句时,发起TestAwait()任务,下面的一句
System.Console.WriteLine(str);
已经被编译器附加到了TestAwait()的末尾。主线程进入TestAwait(),当执行:
string str = await client.GetStringAsync("http://www.baidu.com");
时,发起新任务GetStringAsync()。(编译器已经将await之后的代码都附加到了该方法的末尾,包括由await TestAwait()附加而来的System.Console.WriteLine(str)。)主线程跳出调用,执行:
Thread.Sleep(1000);
这样新任务在执行完成下载之后,连续执行两句:
System.Console.WriteLine(str);
3.疑惑
有一个比较让人疑惑的地方,如果
string str = await client.GetStringAsync("http://www.baidu.com");

在控制台中执行时,则会创建一个新的线程,await之后的语句,都会在这个线程中执行。如果是在UI中执行的,await语句并没有创建新的线程,await之后的语句也都会在主线程中执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值