C# 之 Async/Await

2023-05-31 0 303

Async/Await 已经出来许多年,虽然生前是个老码农,但对C#依然是新手,所以在学习的操作过程中做个历史记录,算第二份把。

为什么须要Async/Await?

为什么须要Async/Await?因为触发器程式设计须要啊!

触发器程式设计不是早有了吗,为什么须要Async/Await?没Async/Await,你总之能用现代手段实现触发器程式设计,建立两个thread,在把干的表达式传达到thread,接着外边继续干别的活,外面干的相差无几了,就去等thread的结果,接着处理意见,搽鼻子….,这叮当下来,几百行标识符列先卡了,除此以外,你自己写的现代形式的标识符还可能将出现各种问题(比如说鼻子没擦干净)。(Chavanges:写了多年的C,表示很难过)

有了Async/Await,你只须要录于标识符就可搞掂,而且更安全,更放心。不香吗?不香吗!

有些老师对触发器程式设计可能将没啥概念,这里举个范例:你在写两个GUI的应用流程,那个流程须要读取两个特别大的文档,那个操作过程可能将须要30s:

假如是并行程式设计商业模式,在读取文档的这30s里头,使用者是不能进行任何人操作形式的,比如说点个按键什么的,换做你,你会不会认为流程是不是挂了(鬼知道文档读取的好不好了?总之smart一点你能搞两个bar来显示,但也须要触发器哦)

假如是触发器程式设计商业模式,你能改到“在前台”读取那个文档,主旋律程依然能serve使用者的操作形式,比如说点个按键啥的,假如使用者要操作形式文档,你能很nice的告诉用户文档正在读取中,读取多少了等等,明显那个使用者新体验较佳。

Async/Await的突破点归纳

先上干,把突破点归纳一下,搞不懂说实话,直接埃唐佩县方可。或许把突破点放前面是因为标识符太长,不想把重点拉到太前面了。

Async是C#的缩排,能用以润色method或是expression,用以新闻稿两个触发器的method或是expression两个触发器的method仅全力支持以下codice:TaskTask<TResult> // C#void // 表述void回到实际上是为了跟一般表达式保持相容任何人包涵可出访GetAwaiter()形式的类型(从C# 7.0已经开始全力支持)Async形式在继续执行的时候,已经开始是以并行的形式执行(即在初始化方的thread里跑的),直到遇到awaitURL,从awaitURL已经开始,C#会另起两个thread来继续执行await前面的标识符。假如Async形式里头的标识符没包涵await的标识符会怎么样?那整个表达式就会并行继续执行,跟一般表达式没差异。C++也会来点警示。

话不多说,上标识符

using System; using System.Threading; public class AsyncAwaitTest { static void Main(string[] args) { Console.WriteLine(“Main start, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); var teaResult = PrepareteaAsync(); var hotWaterResult = PrepareHotWaterAsync(); var cupResult = PrepareCupAsync(); Console.WriteLine(“Main waiting, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); teaResult.GetAwaiter().GetResult(); hotWaterResult.GetAwaiter().GetResult(); cupResult.GetAwaiter().GetResult(); Console.WriteLine($”All Done! tea={teaResult.Status}, hotWater={hotWaterResult.Status}, cup={cupResult.Status}, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); Console.WriteLine(“Main end, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); } private static async Task PrepareteaAsync() { Console.WriteLine(“PrepareteaAsync start, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); await TimeConsumingMethod(3000); Console.WriteLine(“PrepareteaAsync end, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); } private static async Task PrepareHotWaterAsync() { Console.WriteLine(“PrepareHotWaterAsync start, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); await TimeConsumingMethod(5000); Console.WriteLine(“PrepareHotWaterAsync end, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); } private static async Task PrepareCupAsync() { Console.WriteLine(“PrepareCupAsync start, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); await TimeConsumingMethod(2000); Console.WriteLine(“PrepareCupAsync end, Thread ID is ” + Thread.CurrentThread.ManagedThreadId); } static Task<int> TimeConsumingMethod(int timeCost) { var task = Task.Run(() => { Console.WriteLine($”TimeconsumingMethod({timeCost}) start with Thread ID is {Thread.CurrentThread.ManagedThreadId}”); Thread.Sleep(timeCost); Console.WriteLine($”TimeconsumingMethod({timeCost}) end with Thread ID is {Thread.CurrentThread.ManagedThreadId}”); return timeCost; }); return task; } }

运行结果如下:

Main start, Thread ID is 1 PrepareteaAsync start, Thread ID is 1 PrepareHotWaterAsync start, Thread ID is 1 PrepareCupAsync start, Thread ID is 1 Main waiting, Thread ID is 1 TimeconsumingMethod(3000) start with Thread ID is 4 TimeconsumingMethod(2000) start with Thread ID is 7 TimeconsumingMethod(5000) start with Thread ID is 6 TimeconsumingMethod(2000) end with Thread ID is 7 PrepareCupAsync end, Thread ID is 7 TimeconsumingMethod(3000) end with Thread ID is 4 PrepareteaAsync end, Thread ID is 4 TimeconsumingMethod(5000) end with Thread ID is 6 PrepareHotWaterAsync end, Thread ID is 6 All Done! tea=RanToCompletion, hotWater=RanToCompletion, cup=RanToCompletion, Thread ID is 1 Main end, Thread ID is 1

标识符解析

上面用泡茶的范例来解析,简单拆解为3个步骤:准备茶叶,烧已经开始,洗杯子,三个步骤在Main表达式都是并行的,最后等待三者的结果能看到PrepareteaAsync(), PrepareHotWaterAsync(), PrepareCupAsync() 三个表达式的第一行log都是在thread ID为1的进程打印的,而前面的部分都是在各自的子线程里打印出来的。理解这点很重要。在三个触发器线程启动完成后,我们还须要等待回到结果。假如那个时候主旋律程退出的话,那子线程也会随之退出的。在刚已经开始写Console Application的测试code我就遇到那个问题,刚已经开始还加sleep来等,或是干脆写个ReadKey()等,其实用GetAwaiter()才是正解。每个Async形式的回到其实是个Task,关于Task的更多属性能参考前面的链接的内容。

参考链接:

Asynchronous programming in C# | Microsoft Docs

The Task Asynchronous Programming (TAP) model with async and await (C#)” | Microsoft Docs

Async and Await In C# (c-sharpcorner.com)

Understanding async / await in C# – Stack Overflow

Async and Await (stephencleary.com)

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务