Multithreading 为什么异步被认为比多线程性能更好?
我了解异步编程和多线程编程,并且我已经完成了这两项工作,可以轻松地完成它们。然而有一件事仍然困扰着我:为什么人们普遍认为异步比多线程性能更好?(补充:我说的是两种方法都是可行的,你可以做出选择) 乍一看,原因似乎很清楚——线程更少,操作系统调度程序的工作量更少,堆栈空间浪费的内存更少。但是我觉得这些论点站不住脚。让我们分别来看看它们:Multithreading 为什么异步被认为比多线程性能更好?,multithreading,performance,asynchronous,Multithreading,Performance,Asynchronous,我了解异步编程和多线程编程,并且我已经完成了这两项工作,可以轻松地完成它们。然而有一件事仍然困扰着我:为什么人们普遍认为异步比多线程性能更好?(补充:我说的是两种方法都是可行的,你可以做出选择) 乍一看,原因似乎很清楚——线程更少,操作系统调度程序的工作量更少,堆栈空间浪费的内存更少。但是我觉得这些论点站不住脚。让我们分别来看看它们: 操作系统调度器的工作量更少。没错,但这是否意味着总工作量减少了?仍然有N个任务并行运行,必须有人在它们之间切换。在我看来,我们只是从操作系统内核开始工作,并开始在
- 首先,我不知道其他操作系统的情况,但至少在Windows中,线程的堆栈空间不是一次性提交的。有保留的虚拟内存地址,但实际内存仅在需要时提交
- 即使它被提交了,也没什么大不了的,因为仅仅分配内存并不会降低程序的速度。除非你的内存用完了,现代计算机有足够的内存来存储上千个堆栈,尤其是服务器
- 即使堆栈确实被提交并最终导致内存不足,大多数堆栈也只会在开始时使用一点(如果您的程序遇到堆栈溢出,那么您需要担心更大的问题)。这意味着不管怎样,都有可能将其中的大部分内容分页出来
- 大内存使用的真正问题是CPU缓存被大量破坏。当你需要的地方到处都有大量的数据,而CPU缓存跟不上这些数据,需要一次又一次地从主RAM获取数据时,事情就会变得很慢。但是异步编程在这方面没有任何帮助。如果有的话,它会主动使用更多内存。我们现在不再使用精简堆栈框架,而是在堆上为每个堆栈框架分配单独的
对象,这些堆栈框架包含状态和局部变量、回调引用以及所有内容。此外,它在整个地址空间中都是碎片,这给CPU缓存带来了更多的麻烦,因为预取是无用的李>Task
async/await
推出的第一项技术。)
我们使用线程并行化CPU绑定的任务,使用异步IO并行化IO绑定的任务
CPU方面:我们都知道每个任务一个线程是错误的。我们不需要太多线程,因为上下文切换将冻结整个系统。我们不要太少,因为我们希望任务尽快完成。当然,我们正在寻找某种线程池。
ThreadPool是在
任务
之前调度异步任务的默认方式。但是线程池有一个棘手的问题——很难知道异步何时完成,以及异步结果或异常是什么。然后是
任务
。任务不仅在线程池上调度委托,而且在任务完成时,您还可以获得结果或异常,并使用task.ContinueWith
从中继续工作
IO方面:我们都知道每个连接的线程是一件坏事。如果我们想让优化后的服务器每秒处理数百万个请求,我们不能只为每个新连接生成一个新线程。我们的系统将在上下文切换时窒息。所以我们使用异步IO。在
Task
之前的时代,我们使用了BeginRead/EndRead
和BeginWrite/EndWrite
,这两种方法都很容易出错,而且使用起来很痛苦-我们不得不使用糟糕的事件驱动编程模式然后是
任务
。我们可以启动异步IO操作,并通过任务接收结果或异常。继续执行。它使异步IO更易于使用
Task
是连接异步CPU任务和异步IO任务的粘合剂。通过一个接口,我们可以调度一个异步函数,并通过Task.ContinueWith
获得结果。难怪用Task
s编程变得如此流行
任务。ContinueWith
非常不可读和不可写。
基本上,将一个任务链接到一个任务到一个任务到一个任务。。。头痛。正如Node.js开发人员抱怨的那样(即使在jsasync/await
中,将来也会标准化)。async/Wait在这里进行救援。基本上,C#编译器在幕后完成了一个简洁的巫术。简而言之,它接受await
之后的所有内容,并使用状态机对其进行打包,当await
之前的所有内容完成时,将调用状态机。编译器接受同步代码(用async
/wait
注释),并为您执行连续操作
那么,为什么要使用异步
/等待
+任务
而不是多线程代码呢
async
/await
是获取异步结果或异常的最简单方法。(相信我,我用C++编写了异步代码,C语言,java和JavaScript,<代码>异步代码>代码>等待< /COD>是该领域的天堂。
async
/await
可用于CPU绑定任务和IO绑定任务。两个不同但相似字段的相同接口李>
如果您想要异步IO,那么