第一个是日常使用方式的问题:
我们一般在项目中经常见到这样的代码:
var result1=await func1Async();
var result2=await func2Async();
var finalResult=await funcFinal(result1,result2);
这种写法其实result2要等result1执行完了才去执行,他们2个是同步执行的了,
写成下边这种才是异步执行的,但很少见有这样写的:
就这2个问题,谢谢大家的回答.
1.可以那种写法,首先很冗余人工劳作,再次可能会出现问题——在你执行创建(并执行)Task2的时候,已经没有机会await Task1了;
await的目的是把并行 执行方便的串行执行,既然串行当然得一个一个来。
2.简单聊一下——
设没有Task,只有Thread,你怎么实现一个类似Task。既然创建Thread开销很大且并发量很大的时候存在很多问题(如数量限制,性能急速下降),首先想到用ThreadPool(内置或者自己实现均可),但仍存在设定的第一个创建Thread开销的问题(首先去用一下Thread才会明白,Thread必须每次新创建)。那么针对Thread的问题,如何解决不就出来了,如容量条件下不干掉Thread,就像你用SqlServerConnection(之所以第二次快,不要以为Colse了,底层模块就完全归零,只是你的代码成归零了而已)。
现在你不得不在构建的这种模式下创建一个通用对象,且叫Task吧;
现在还有多少常用问题需要处理?——传统的Thread并发等待。假设抛开内置已经实现的函数,如何对多个Thread进行等待呢,这是机器擅长的事——不停的往复检查状态即可。但现在你面临的问题已经不是Thread,而是Task,呃,因此面临的问题比较多,比如超出Thread池怎么办,对还需要一种简单的实现单个和多个Task的等待方式(用之前的Thread不得不很麻烦的写很多代码,await就很方便了)。
自从移动互联网后特别流行吹概念,比如其他语言的协程~~概念上这玩意儿个人认为可以相当。随便怎么玩,机器的核心就是往复、重复,如果想把计算机械化,用电机也可以驱动。单核没有没有真正意义的并发执行,只有概念上的意义,单片机可能裸跑,没有进程概念,可能直接就是 晶振的Loop 入口。
随便聊聊,希望对你有帮助。
第1个问题中,即使是没有机会await(耗时很少,await时已经执行完成了,await会直接返回结果)也不影响执行嘛,
我尝试把下边代码中的3000改为1,结果也是正常的
using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace AsyncBreakfast { class Program { static async Task<string> MethodA() { await Task.Delay(3000); return "A"; } static async Task<string> MethodB() { await Task.Delay(3000); return "B"; } static async Task MainB(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); var aResult = await MethodA(); var bResult = await MethodB(); sw.Stop(); Console.WriteLine(aResult); Console.WriteLine(bResult); Console.WriteLine($"耗时:{sw.ElapsedMilliseconds} 毫秒.");//6+ Console.Read(); } static async Task Main(string[] args) { Stopwatch sw = new Stopwatch(); sw.Start(); var maTask = MethodA(); var mbTask = MethodB(); var aResult = await maTask; var bResult = await mbTask; sw.Stop(); Console.WriteLine(aResult); Console.WriteLine(bResult); Console.WriteLine($"耗时:{sw.ElapsedMilliseconds} 毫秒.");//3+ Console.Read(); } } }
@hexllo: 自己慢慢品和理解。
1.你的两种写法,貌似没区别result2要等result1执行完了才去执行,那谁会把代码往多的写呢?
2.【async await不是在一个新的线程中执行的】这个不绝对,也有可能是同一个线程中执行,状态机中的代码分析一下就知道,程序在立刻返回的情况下会选择同步执行,所以有时候也是在同一个线程中执行,这个只是语法糖,当然你说的也对的执行确实通过线程池干的。
1。 写法2没有问题。但需要注意,T2 和 T1的结果不能有依赖关系。
2。asyc/await 通常用于IO操作方面。在读写数据时,等待IO完成的时候把控制权交给操作系统,当前线程就会被回收。待IO完成时,操作系统会通知代码继续执。单纯的计算操作,没必须async
写法没问题,你说的「异步」我猜更多指的是「并行」(和「串行」相反),就是两个 Task 同时开始。至于说少见的原因可能是大家都用 Task.WhenAll()
吧 😃,更多时候可能还是 Fire and Forget。
如果本身有多个事情在竞争资源意义就不太大了(比如 web server,本身请求就很多,你这边 await 了,线程就可以让给别的请求,不会出现没事干的情况)。
原文说的是 await 关键字不会创建线程,await 不是创建线程的原因,await 只是会把当前线程让出来。是具体在 await 的方法执行的时候可能会创建线程。
await TaskA
do something B
我来回答下第二个问题,Async/Await 会在当TaskA完成之后把 do something B 分配给线程池里的线程去执行(.Net Core). 线程池里的线程你不知道是新创建的线程还是已有的线程。
.Net IO异步最关键的是线程池里的IO thread,在你的程序进行IO请求的时候,不需要任何线程进行监听,当IO请求返回结果时会有一个IO thread被call 然后执行do something B,这才真正意义上的异步,有了这个,Async/Await才有意义,而Async/Await不过是一个语法糖,生成一个状态机,在执行到await TaskA的时候就返回一个Task,然后把do something B 变成一个call back action,并且TaskA的网络请求完成的时候,将call back action扔给IO thread 执行,最后Set result in Task.
在没有async/await 之前.net 还有别的方法去利用IO thread实现异步。
这个和Task.Run时完全不同的,Task.Run时并行,Async是异步,但是并行却是异步实现的一种方式。
比起Task.Run, Async的异步是利用最少的线程资源实现异步