异步(async、await)

article/2025/9/18 3:45:30

同步与异步

同步:如果一个程序调用某个方法,等待其执行所有处理后才继续执行,我们就称这样的方法是同步的,这是默认的形式
异步:异步的方法在处理完成之前就返回到调用方法,C#的async/await特性可以创建并使用异步方法。

async/await特性的组成

(1)调用方法:该方法调用异步方法,然后在异步方法(可能在相同的线程,也可能在不同的线程)执行其任务的时候继续执行
(2)异步(async)方法:该方法异步执行其工作,然后立即返回到调用方法
(3)await表达式用于异步方法内部指明需要异步执行的任务一个异步方法可以包含任意多个await表达式,不过如果一个都不包含的话编译器会发出警告

异步方法的定义规则

(1)方法头中包含async方法修饰符它在返回类型之前。
(2)包含1个或多个await表达式,表示可以异步完成的任务
(3)方法的返回类型voidTaskTask<T>中的一种,Task和Task<T>的返回对象表示将在未来完成的工作,调用方法和异步方法可以继续执行。
void:如果调用方法仅仅想执行异步方法,而不需要与它做任何进一步的交互时,异步方法可以返回void类型,这时即使异步方法中包含任何return语句,也不会返回任何东西。
Task:如果调用方法不需要从异步方法中返回某个值,但需要检查异步方法的状态,那么异步方法可以返回一个Task类型的对象,这时,即使异步方法中出现了return语句,也不会返回任何东西

Task<T>:如果方法要从调用中获取一个T类型的值,异步方法的返回类型就必须是Task<T>,调用方法将通过读取Task的Result属性来获取这个T类型的值。

(4)任何返回Task<T>类型的异步方法其返回值必须为T类型或可以隐式转换为T的类型
(5)异步方法的参数可以为任意类型任意数量,但不能为out、ref参数
(6)按照约定,异步方法的名称应该以Async为后缀
(7)除了方法以外,Lambda表达式和匿名方法也可以作为异步对象。

异步方法结构

(1)第一个await表达式之前的部分:从方法开头到第一个await表达式之间的所有代码,这一部分应该只包含少量且无需长时间处理的代码。
(2)await表达式:表示被异步执行的任务
(3)后续部分:在await表达式以后出现的方法中的其余代码,包括其执行环境,如所在线程信息、目前作用域的变量值,以及当await表达式完成后要重新执行所需的其他信息。

异步方法控制流

调用异步方法后,从第一个await表达式之前的代码开始,正常(同步)执行直到遇见第一个await,这一区域实际上在第一个await表达式处结束,此时await任务还没有完成(大多数情况下)。当await任务完成时,方法将继续同步执行,如果还有其他await,就重复上述过程。

当达到await表达式时,异步方法将控制流返回到调用方法(实际上并不是一遇见await就返回控制流,需要根据实际情况来定)如果方法的返回类型为TaskTask<T>类型将创建一个Task对象,表示需异步完成的任务和后续,然后将该Task返回到调用方法

public class Program{static void Main(string[] args){async Task<int> func(){Console.WriteLine("func");await Task.Run(() => Thread.Sleep(5000));return 10;}async Task<int> foo(){Console.WriteLine("foo");var v = await func();Console.WriteLine("foo1");Console.WriteLine(v); //10Console.WriteLine("foo2");return 100;};Console.WriteLine("before foo");var r = foo();Console.WriteLine("after foo");Console.WriteLine(r.Result);  //100Console.ReadLine();}}

先打印到after foo,5秒后打印剩余内容

个人理解:可以理解为凡是在异步函数中遇见await时,其后续的程序代码,必须要等await操作结束返回来后再继续执行,而当调用到嵌套异步函数中真正需要等待处理的任务时,才会返回控制流到调用方法,在遇见第一个await时,控制流还是会进入func函数,所以会先打印func,然后遇见第二个await时才会真正的返回控制流到调用函数foo(),而foo的后续也需要等待func处理完成之后才能执行,所以继续返回控制流到调用Main,然后Main继续执行打印after foo,当Main想要打印r.Result的时候,则需要等待foo执行完并return。

目前有俩个控制流:异步方法内和调用方法内的,异步方法内的代码完成以下工作,异步执行await表达式的空闲任务,当await表达式完成时,执行后续部分,后续部分本身也可能包含其他await表达式,这些表达式也将按照相同的方式处理,即异步执行await表达式,然后执行后续部分。当后续部分遇到return语句或到达方法末尾时,如果方法返回类型为void,控制流将退出,如果方法返回类型为Task,后续部分设置Task的属性并退出,如果返回类型为Task<T>,后续部分还将设置Task对象的Result属性。

同时,调用方法中的代码将继续其进程,从异步方法获取Task对象,当需要其实际值时,就引用Task对象的Result属性,届时,如果异步方法设置了该属性,调用方法就能获得该值并继续,否则将暂停并等待属性被设置,然后在执行

    class A{static public void DoRun(){var t = foo();Console.WriteLine(t.Result);}static private async Task<int> foo(){var t1 = Task.Run(() =>{Thread.Sleep(100);return 100;   //设置Task对象的Result属性});var t2 = Task.Run(() =>{Thread.Sleep(200);return 200;   //设置Task对象的Result属性});await Task.WhenAll(new List<Task<int>>() { t1, t2 }); //异步等待集合内的Task都完成,不会占用主线程的时间return t1.Result+t2.Result;}}public class Program{static void Main(string[] args){A.DoRun();}}

await表达式

await表达式指定了一个异步执行的任务await关键字和一个空闲对象(称为任务)组成,这个任务可能是一个Task类型,也可能不是,默认情况下,这个任务在当前线程异步运行。

一个空闲对象即是一个awaitable类型的实例,awaitable类型是指包含GetAwaiter方法的类型,该方法没有参数,返回一个称为awaiter类型的对象,awaiter类型包含以下成员
(1)bool IsCompleted {get;}
(2)void OnCompleted(Action);
它还包含以下成员之一:
(1)void GetResult();
(2)T GetResult(); (T为任意类型)
实际上,并不需要构建自己的awaitable,相反,应该使用Task类,它是awaitable类型,作为await表达式的任务,最简单的方式是使用Task.Run方法来创建一个Task,关于Task.Run,有一点非常重要,即它是在不同的线程上运行你的方法
Task Run(Func<TReturn> func)   这个是Run函数众多重载版本中的其中一个,参数为一个委托类型,这个委托没有参数,返回值类型为TReturn,因此要将你的方法传递给Task.Run方法时,需要基于该方法创建一个委托。

取消一个异步操作

当我们想要终止异步执行时,可以通过类CancellationToken和类CancellationTokenSource来实现,拥有CancellationToken对象的任务需要定期检查其令牌(token)状态,如果CancellationToken对象的IsCancellationRequested属性为true,任务需停止其操作并返回CancellationToken是不可逆的,并且只能使用一次,也就是说,一旦IsCancellationRequested属性被设置为true,就不能更改了。

CancellationTokenSource对象创建可分配给不同任务的CancellationToken对象,任何持有CancellationTokenSource的对象都可以调用其Cancel方法,这会将CancellationToken的IsCancellationRequested属性设置为true

    class MyClass{public async Task RunAsync(CancellationToken ct){if (ct.IsCancellationRequested){Console.WriteLine(1111);return;}await Task.Run(() => CycleMethod(ct), ct);}void CycleMethod(CancellationToken ct){Console.WriteLine("Starting CyclyMethod");const int max = 5;for (int i = 0; i < max; i++){if (ct.IsCancellationRequested){Console.WriteLine("退出");return;     //退出}Thread.Sleep(1000);Console.WriteLine("{0} of {1} iterations completed", i + 1, max);}}}public class Program{static void Main(string[] args){CancellationTokenSource cts = new CancellationTokenSource();CancellationToken token = cts.Token;MyClass mc = new MyClass();Task t = mc.RunAsync(token);Thread.Sleep(3000);  //等待3秒cts.Cancel();        //取消异步t.Wait();    //等待这个Task完成执行过程Console.WriteLine("Was Cancelled:{0}", token.IsCancellationRequested);}}

输出为:

Starting CyclyMethod
1 of 5 iterations completed
2 of 5 iterations completed
3 of 5 iterations completed
退出
Was Cancelled:True

t.wait会等待这个Task结束后在继续向下执行,如果没有这行代码,主程序会提前打印最后一样代码,然后退出,这样就会少输出一定内容,这和之前所说的一样,假如异步方法返回的是Task<int>类型,那么如果在主程序中如果使用到该返回的Result字段,则会等待这个值被赋值了之后再继续向下走,否则主程序不会等待异步方法。

在调用方法中同步地等待任务(Wait)

调用方法可以调用任意多个异步方法并接收它们返回的Task对象,然后你的代码会继续执行其他任务,但在某个点上可能需要等待某个特殊Task对象完成,然后再继续,为此Task类提供了一个实例方法Wait,可以在Task对象上调用该方法。
Wait:用于等待单一Task对象
WaitAll(静态方法):用于等待一组Task中所有任务都结束
WaitAny(静态方法):用于等待一组Task中某一个任务结束

在异步方法中异步地等待任务(WhenAll、WhenAny)

有时在异步方法中,会希望用await表达式来等待Task,调用到await时异步方法会返回到调用方法,然后异步方法执行自己的流程,可以通过Task.WhenAllTask.WhenAny来实现等待一个或所有任务完成,然后接着执行后面语句。例如tasks是多个任务的集合,当调用到await Task.WhenAll(tasks); 则等待集合内所有任务都完成再继续走下面的代码,如果换成Task.WhenAny则集合内只要有一个任务完成则就走下面的代码。

Task.Delay方法

Task.Delay方法创建一个Task对象,该对象将暂停其在线程中的处理,并在一定时间之后完成,与Thread.Sleep阻塞线程不同的是,Task.Delay不会阻塞线程,线程可以继续处理其他工作。

Task.Yield

Task.Yield方法创建一个立即返回的awaitable,等待一个Yield可以让异步方法在执行后续部分的同时返回到调用方法。可以将其理解成离开当前的消息队列,回到队列末尾,让处理器有时间处理其他任务。

    static class DoStuff{public static async Task<int> FindSeriesSum(int i1){int sum = 0;for(int i=0;i<i1;i++){sum += i;if (i % 10 == 0){Console.WriteLine("前");await Task.Yield();Console.WriteLine("后");}}return sum;}}public class Program{static void Main(string[] args){Task<int> value = DoStuff.FindSeriesSum(100);Console.WriteLine(111);Console.WriteLine(value.Result);Console.ReadLine();}}

 


http://chatgpt.dhexx.cn/article/UxFVPHaA.shtml

相关文章

async/awiat和promise之间的区别

今天看到了一段代码 async function async1() {console.log(async1 start);await async2();console.log(async1 end); } async function async2() {console.log(async2); } console.log(script start); setTimeout(function() {console.log(setTimeout); }, 0) async1(); new …

什么是异步

文章目录 前言一、异步是什么&#xff1f;二、举个例子来理解异步 1.异步最典型的例子就是“回调函数”总结 前言 在vue的过程中&#xff0c;我们一定会遇到诸如&#xff1a; function&#xff08;参数&#xff09;.then(res>{}) 形式的代码。到底怎么编译执行的呢 &#x…

Spring Boot 基础学习之(五)页面通过自定义LocaleResolver组件实现网页页面的的中英文转换

本次项目所有能够使用的静态资源可以免费进行下载 静态资源 在前端网页&#xff0c;是不是看见过这样的功能 基础网页&#xff1a;中文表示 点击下面的English 按钮网页显示文字开始切换 通过功能性按钮实现中英文切换&#xff0c;在浏览器中&#xff0c;都带着一个功能叫翻…

网页中文转英文(国际化)

背景&#xff1a; 我的项目是已经完成的项目&#xff0c;因为要拓展海外市场&#xff0c;需要支持英文。 采用的方式是添加配置文件&#xff0c;见下文详细步骤。 本文基本转自&#xff1a;http://blog.csdn.net/wuhawang/article/details/52228589 在他的基础上给大家一点提示…

英语数字转换器

英语数字转换器 STL中map&#xff0c;stack和string的运用 描述&#xff1a; 在这个问题中&#xff0c;将用英语给你一个或多个整数。你的任务是将这些数字转换成整型表示。数字范围从-999,999,999到999,999,999.下面是你的程序必须考虑的详尽的英语单词表&#xff1a; neg…

Unity 中英文转换

在Resources下创建文件夹LanguageTxt&#xff0c;再其创建“Chinese.txt”及“English.txt”&#xff08;记得保存文本时选择UTF-8&#xff09; Chinese.txt Btn:这是一个按钮 English.txt Btn:This is a button 在Scripts下创建“LanguageManager.cs”及“UIText.cs” L…

SAP中英文转换--中文转英文

中文转英文-函数&#xff1a;CONVERSION_EXIT_CUNIT_INPUT CALL FUNCTION ‘CONVERSION_EXIT_CUNIT_INPUT’ EXPORTING input “输入的中文单位 IMPORTING output “输出的英文单位 效果图&#xff1a;

SAP 中英文转换-英转中

英文转中文-函数&#xff1a;CONVERSION_EXIT_CUNIT_OUTPUT CALL FUNCTION ‘CONVERSION_EXIT_CUNIT_OUTPUT’ EXPORTING input “输入的英文单位 IMPORTING output “输出的中文单位

将数字转换为中文

功能需求 做公司项目遇到一个有关交易金额&#xff08;合同签订书&#xff09;的内容&#xff0c;需要将查询出来的交易金额转化为中文数字&#xff0c;例如&#xff1a;壹拾捌万伍仟元整&#xff08;185000.00&#xff09; 需求分析 因为合同书中的数据都是动态的&#xff0c…

Java 16进制报文转换中英文报文(通过字节转换)

最近在搞这个16进制报文,网上找了很多地方&#xff0c;解出来的结果不是乱码就是报错&#xff0c;干脆自己写了。 大概是这样的&#xff0c;16进制的报文大家都知道是什么样子 例如: 3C E4 BA A4 E6 98 93 E6 88 90 E5 8A 9F EF BC 81 3E 20 3C 42 61 6B 31 2F 3E 因为其中包…

通过C#进行中英文转换

通过C#进行中英文转换 编写相应语言的XML文件&#xff0c;添加xml文件 ChineseSimplified.xml文件内容 <?xml version"1.0" encoding"GB2312" ?> <Softimite Language"12"><Form><Name>LoginForm</Name><…

【Adobe After Effects中英文转换2019——2023版】

** Adobe After Effects中英文转换2019——2023版 ** 如果是默认安装的软件&#xff0c;在桌面右击AE图标&#xff0c;点击打开文件所在位置&#xff0c;来到软件安装目录 C:\Program Files\Adobe\Adobe After Effects 2023\Support Files 找到AMT文件夹 点击进入&#xf…

在线中英文符号转换工具

在线中英文符号转换工具 在线中英文符号转换工具 将中文符号转换成英文符号或将英文符号转换成中文符号&#xff0c; 将单引号‘’都转换成’&#xff0c; 将双引号“”都转换成" 将中括号【】转换成[]&#xff0c; 将大括号&#xff5b;&#xff5d;转换成{} 将逗号&…

英文表格如何快速转换为中文?

今天跟大家分享一下英文表格如何快速转换为中文&#xff1f; 1.首先打开Excel文件&#xff0c;选中要翻译的单元格&#xff0c;点击【DIY工具箱】 ​ 2.点击【翻译】 3.选择【有道翻译】 4.将翻译语言设置为中文&#xff0c;然后点击【确定】 5.鼠标点击一个合适的单元格作为翻…

英文转换-在线英文批量转换器免费

英文转换&#xff0c;怎么找到好的英文转换器&#xff1f;今天给大家分享一款免费批量的英文转换器汇集了世界最好的几个翻译平台&#xff08;百度/谷歌/有道&#xff09;&#xff0c;为什么这么多人使用它&#xff1f;首先第一点翻译质量高&#xff0c;选择性多。第二点可以批…

php 英文转中文,中文转换成英文

[php]代码库/** * 中文转换成英文 */ function pinyin($_String, $_Codegb2312){ $_DataKey "a|ai|an|ang|ao|ba|bai|ban|bang|bao|bei|ben|beng|bi|bian|biao|bie|bin|bing|bo|bu|ca|cai|can|cang|cao|ce|ceng|cha". "|chai|chan|chang|chao|che|chen|cheng|c…

C#小知识之中英文转换、去空格

一、中英文转换 1、安装NPinYin 2、编写代码 string str "这里是测试的中文字符串"; string str1 Pinyin.GetChineseText(str); string str2 Pinyin.GetInitials(str); string str3 Pinyin.GetPinyin(str);Console.WriteLine("取和拼音相同的汉字列表&…

Qt 语言家实现中英文切换(解决纯代码添加部件的中英文转换问题)

Qt 语言家实现中英文切换&#xff08;解决纯代码添加部件的中英文转换问题&#xff09; 关于.ts和.qm文件的生成&#xff0c;更新翻译、发布翻译等步骤就不多说了&#xff0c;其他博主有大量的描述。 现在我要解决的是中英文未完全转换的问题如下图&#xff1a; 如上图所示&a…

系统的学习网络编程,这篇就够了!(来收藏夹里吃灰)

主机字节序和网络字节序&#xff1a; 在32位机器上&#xff0c;累加器一次能装载4个字节&#xff0c;这四个字节在内存中排列顺序将影响它被累加器装载成的整数的值 大端字节序&#xff08;网络字节序&#xff09;&#xff1a;一个整数的高位字节存储在内存的低地址处 小端字节…

玩转RT-Thread之荔枝派Nano(全志F1C100S) 新手上路

玩转RT-Thread之荔枝派Nano(全志F1C100S) 一、新手上路 --作者&#xff1a;燕十三(flyingcys) blog:http://blog.csdn.net/flyingcys --荔枝派nano/RTT非官方群&#xff1a;711174828 在此感谢 RT-Thread官方成员uestczyh222提供的荔枝派Nano内核移植、rttbootloader文件、…