• C#-异步方法关键字async和await


    async关键字和await是配套使用的异步方法语法糖,配合Task类可以使多线程变得有序,

    也可以自己实现一套协程功能。

    async关键字(异步方法)

    async关键字是C#特有的。Java没有这玩意。

    async在C#世界里是上下文关键字。它只有在修饰一个方法的时候才自动被编译器识别为

    关键字,在代码的其他位置上可以被用作变量名等其他任何用途。

    asyn关键字用来修饰两类方法:lambda表达式或则异步方法。

    拥有async修饰的方法称为async方法,比如:

    1 Public Task ExampleMethodAsync(){

    2 //(1)To do some code here synchronously...(在这里同步做一些代码…)

    3 await......//(2)To do something asynchronously.(异步地做某事。)

    4 //(3)To do some code here after awiat code.(在awiat代码之后做一些代

    码。)

    5 }

    就如上⾯这个⽅法ExampleMethodAsync(),微软爷爷特别喜欢在定义异步函数名字后习

    惯加个Async后缀(这不是必须的,加不加编译器既不会报错,也不会影响异步特性),告

    诉我们这个⽅法是个异步⽅法。我们在⾃⼰定义异步⽅法的时候,也可以照搬这个微软

    的习惯。

    asyncawaitawait修饰的⽅法内部,应当出现⼀个关键字,两个关键字⼀般成对出现。当

    然,如果我们不⼩⼼忘记写表达式或者语句,这asyncawaitasyncawait个⽅法默认按照同

    步⽅式运⾏,同时,编译器会友好地提⽰我们是不是漏写了。此外,⽅法内部,可以有

    多个语句。

    awiat运⾏的语句,⼀般都是⽐较费时的任务(也就是会阻塞主线程的⼀些操作,⽐如获

    取Http应答,写⼊⽂档,保存数据库等),要不然就不需要异步了。

    以上⾯的例⼦为例(假设例⼦中的是第⼀个),异步⽅法执⾏过程(⽐较粗的看):

    1.主线程进⼊⽅法ExampleMethodAsync()后,先顺序执⾏(1):如果(1)当中有创建Task或

    Task的语句,或者是调用其他async方法(返回值是Task或者Task),为了描述⽅便,我们都称为Task创建语句,⽐如直接创建⼀个Task或

    Task:

    1 var tsk= Task.Run(() =>{

    2 Thread.Sleep(1000) ;

    3 Console.Writeline("异步执行另一个任务。");

    4 });

    或者调⽤另外⼀个async⽅法

    1 Task getStringTask =

    client.GetStringAsync("https://docs.microsoft.com/dotnet")

    那么,在调⽤完Task创建语句的时候异步任务就已经开始运⾏了(这个语句调⽤本⾝是

    在主线程当中,内部的任务则是新的线程中执⾏),也就是此时异步的线程已经启动

    了,由于它是异步启动的,所以它并不会阻⽌主线程继续往下⾛;

    2.接下来,主线程会顺序运⾏到async⽅法内部的第⼀个await,如果第⼀个await调⽤的

    仍然是⼀个async⽅法,那么主程序继续进⼊这个⽅法执⾏,⼀直到碰到⼀个await task

    为⽌,主线程才会跳出ExampleMethodAsync⽅法;举个例⼦:

    1 using System.Threading.Tasks;

    2

    3 namespace ConsoleApp1

    4 {

    5 internal class Program

    6 {

    7 static void Main(string[] args)

    8 {

    9 //做某事

    10 ExampleMethodAsync();

    11 //做其他事情...

    12

    13 }

    14 public static async void ExampleMethodAsync()

    15 {

    16 //(1)执行一些任务 Do2Async()前准备的事情...

    17 await Do2Async();//(2)18 //(3)运行一些Do2Async()执行完之后的事情...

    19 }

    20 public static async Task Do2Async()

    21 {

    22 //执行一些 t任务执行前的事情,比如任务的准备...

    23 Task t = Task.Run(() =>

    24 {

    25 //异步任务中执行费时的事情...

    26 });

    27 await t;

    28 //在这里执行一些t 任务执行完相关的事情...

    29 }

    30 }

    31 }

    32

    调⽤⽅(也就是main所在的主线程)会⼀直执⾏到20⾏才跳出ExampleMethodAsync()⽅

    法,⽽不是在第10⾏。

    4.ExampleMethodAsync()⽅法中剩余的(3)在执⾏完await(2)部分的内容才执⾏。

    5.假设ExampleMethodAsync()中有第⼆个,第三个…awiat,因为主程序已经跳出来了,

    后续的await会在异步线程中按顺序执⾏下去。

    async⽅法可以是下⾯三种返回类型:

    Task

    Task

    void 这种返回类型⼀般⽤在event事件处理器中%2C或者⽤在你只需要任务执⾏,不

    关⼼任务执⾏结果的情况当中。

    任何其他具有GetAwaiter⽅法的类型(从C#7.0开始)

    注意,我们⽆法等待(awiat)⼀个async void ⽅法。

    1 using System;

    2 using System.Threading.Tasks;

    3 using System.Threading;

    4

    5 namespace ConsoleApp1

    6 {

    7 internal class Program

    8 {9 static void Main(string[] args)

    10 {

    11

    12 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} Hello,I am Caller!");

    13 DoAsync();

    14 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} Hello,I am Caller too!");

    15 Console.Read();

    16 }

    17 public static async void DoAsync()

    18 {

    19 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} In DoAsync(),before

    SunAsync()");

    20 await SunAsync();

    21 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} After SunAsync(),DoAsync()

    End.");

    22 }

    23 public static async Task SunAsync()

    24 {

    25 var t = Task.Run(() => {

    26 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} New Task~");

    27 for (int i = 0; i < 10; i++)

    28 {

    29 Thread.Sleep(1000);

    30 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} I am playing game...");

    31 }

    32 });

    33 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} After Task, before await.");

    34 await t;

    35 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} After await,before SunAsync()

    exit.");

    36 }

    37 }

    38 }

    此时的结果:仔细阅读这段代码和结果,细⼼体会,这段代码是ansync void⽅法嵌⼊调⽤ansync Task

    ⽅法。要注意体会,并不是说⼀遇到await主程序(ansync ⽅法的调⽤⽅)就⽴即退出

    DoAsync()⽅法,⽽是执⾏到33⾏,碰到了第⼀个的Task才跳出来。从这个例⼦的输出

    ThreadID号中 可知,33⾏await之后的内容都是在新的线程(4线程)中运⾏的。⽽33⾏

    await之前的内容都在主线程(1线程)中运⾏。⽽33⾏await之前的内容都在主线程(1线程)

    中运⾏。

    如果将SunAsync()代码改为(await之前增加⼀个Thread.Sleep(150000))

    1 public static async Task SunAsync()

    2 {

    3 var t = Task.Run(() => {

    4 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} New Task~");

    5 for (int i = 0; i < 10; i++)

    6 {

    7 Thread.Sleep(1000);

    8 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} I am playing game...");

    9 }

    10 });

    11 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} After Task, before await.");

    12 Thread.Sleep(15000);//主线程睡15秒

    1314 await t;

    15 Console.WriteLine($"ThreadID:

    {Thread.CurrentThread.ManagedThreadId} After await,before SunAsync()

    exit.");

    16 }

    因为,Task.Run()的任务在运⾏到await之前就结束了,因此,await后的内容仍然在主线

    程(1线程)中执⾏。这个例⼦告诉我们,如果任务在await之前就已经执⾏完毕,那么

    await后的内容仍然保留在原线程中执⾏。

    总之,async⽅法调⽤⽅在碰到⼀个实际的await task的时候才退出async⽅法体。⼀般在

    await之前处理与异步任务⽆关的事情(这部分代码是由异步⽅法的调⽤⽅所在的线程执

    ⾏),await之后的代码则是处理异步任务处理完后的事情,因此这部分代码就可以处理

    与异步任务相关的事情(这部分⼀般来说是在新建的异步线程中执⾏的,除⾮在调⽤

    await之前任务就已经很快的执⾏完了,那么这部分内容也可能仍然在调⽤⽅线程中执

    ⾏)。

  • 相关阅读:
    css定位及定位和浮动的区别
    基于局部自适应阈值分割和Hough变换的答题卡识别算法-含Matlab代码
    阿里云视频点播+项目实战
    呼之欲出的jvs低代码以及其他产品2.1.6版本能力大更新
    C++的std::function
    web前端期末大作业 html+css+javascript火影忍者网页设计实例 动漫网站制作
    LiveGBS流媒体平台GB/T28181功能-国标设备通道分享手机PC浏览器观看直播
    JVM篇---第十篇
    大家都在用哪些敏捷开发项目管理软件?
    python 里面对于字典进行key或value排序输出
  • 原文地址:https://blog.csdn.net/New_BoKe/article/details/125904521