参考:
.NET进阶篇06-async异步、thread多线程3 - 知乎 (zhihu.com)
C# Async/Await: 让你的程序变身时间管理大师_哔哩哔哩_bilibili
Demo:
https://files.cnblogs.com/files/summerZoo/Async_Sync_Parall.zip?t=1647483780
https://files.cnblogs.com/files/summerZoo/AsyncAwait.zip?t=1647483856
异步——一个cpu在执行某个线程,遇到等待(比如I/O场景,等待数据库返回数据),它可以去执行其他任务,若当前等待结束,再由它或其他cpu执行核心去继续执行
理解:妈妈现在需要做饭,她将饭洗好放到电饭锅,按下煮饭键。然后她就去炒菜了,而不用等着米饭煮好了再去炒菜(同步),这就是异步。
异步不一定能提高单项工作的效率(米饭还是要煮半个小时、炒菜还是需要花费10分钟),但是可以提升应用程序的处理效率(在一定时间范围内做更多工作)。比如妈妈是一台服务器,半小时内她就处理了煮饭、炒菜两项请求。
应用场景:IO密集型(1、跟第三方交互的(非托管资源,经常有async版本)2.数据库openAsync-Redis交互 3.Web请求-Api 4.文件读取)
并发——创建多个线程,同一时间他们都能竞争cpu执行的时间片。
理解:现在需要做饭,需要切菜(线程一)、生火(线程二)、煮饭(线程三)这三个前期准备工作可以同时进行,为了提升效率,妈妈让儿子、丈夫、自己三个人(多个cpu执行核心)去做这三件事。这就是并发执行。但是计算器。
应用场景:CPU计算密集型(计算耗时操作)
常用异步操作:异步IO
现在,让我们假定要实现一个Wb应用程序,每个客户端请求抵达服务器时,都需要发出一个数据库请求。一个客户端请求抵达时一个线程池线程会调用你的代码。如果现在以同步方式发出一个数据库请求,线程会阻塞不确定的时间,等待数据库返回一个结果。在此期间,如果另一个客户端请求抵达,线程池会创建另一个线程,这个线程在发出另一个数据库请求后,同样会阻塞。随着越来越多的客户端请求抵达,创建的线程也越来越多,所有这些线程都阻塞并等待数据库的响应。结果是Wb服务器分配大量根本不会使用的系统资源(线程及其内存)!更糟的是,数据库真的会用各种结果来响应这些请求。线程被解锁,全都开始执行。但是,由于可能运行了大量线程,同时CPU内核只有区区几个,所以Windows被迫执行频繁的上下文切换,这进一步损害了性能。这和实现一个可伸缩应用程序的初衷是完全背道而驰的。
异步IO
Task异步
async/await
1、在采用 await AyncMethod调用异步方法AyncMethod时,主线程释放返回线程池,线程池拿到一个空闲的可执行的线程执行AyncMethod内的内容,这个空闲的线程有可能是主线程.
2、在await AyncMethod执行完成后,线程池拿到一个空闲的可执行的线程B执行AyncMethod后的内容
AyncMethod是一个耗时比较短的操作,B线程大概率会是执行AyncMethod的线程,这和clr的就近优化调度有关;
比如服务员会在客人点餐完成后上茶水,服务员A(线程1)给了顾客甲一个菜单让顾客点菜(模拟一个异步操作),然后准备去忙其他事情(释放当前线程),没想到没走两步,顾客甲说点好了(耗时短的操作),那么很大可能还是服务员A给顾客上茶水,这样最高效。
AyncMethod是一个耗时比较长的操作,B线程大概率会是线程池随机的一个空闲线程;
同样是点菜的例子,如果服务员把菜单给顾客甲之后,顾客甲说等朋友到了再点菜(耗时长的操作),半小时后朋友才来点好。这个时候肯定是老板随机让当前空闲的一个服务员去上茶水