我对async/await的理解,它是如何工作的以及它的好处,对吗?

w.b*_*ian 18 .net task-parallel-library async-await

我曾经多次断言我对async/await的理解,经常就我是否正确进行辩论.如果有人能够证实或否认我的理解,并清除任何误解,以便我不传播错误信息,我真的很感激.

高级别的理解

async/ await是一种在编写异步代码时避免回调地狱的方法.正在执行异步方法的线程在遇到线程池时将返回线程池await,并在等待的操作完成后将执行该操作.

低级别的理解

JIT会将异步方法拆分为await点周围的离散部分,允许在保留方法状态的情况下重新进入方法.在封面下,这涉及某种状态机.

与并发的关系

async/ await并不意味着任何形式的并发.使用async/ 编写的应用程序await可以完全是单线程的,同时仍然可以获得所有好处,就像node.js尽管有回调一样.与node.js不同,.NET是多线程的,因此通过使用async/ await,您可以获得非阻塞IO的好处,而无需使用回调,同时还具有多个执行线程.

好处

async/ await释放线程以在等待IO完成时执行其他操作.它还可以与TPL一起使用,以在多个线程上执行CPU绑定工作,或者在UI线程之外执行CPU绑定工作.

为了从非阻塞IO中受益,需要在API之上构建异步方法,这些API 实际上利用了最终由OS提供的非阻塞IO.

滥用

这是我理解中最大的争论点.很多人认为在a中Task使用阻塞操作并使用async/ await会带来性能提升.通过创建一个额外的线程来处理操作,将原始线程返回到线程池,然后在任务完成后恢复原始方法,所有发生的都是不必要的上下文切换,而不是真正释放线程来完成其他工作.虽然这并不像TPL那样滥用async/ await,但这种心态似乎源于对async/ 的误解await.

i3a*_*non 14

这非常正确.

但是有一些注意事项:

  • 开始执行异步方法的线程是调用者的线程,它可能是也可能不是ThreadPool线程.
  • 如果达到await,但是等待(通常Task)已经完成,则线程将继续同步执行方法的其余部分.
  • 恢复运行该方法的ThreadPool线程通常是一个线程,但这取决于SyncrhonizationContextTaskScheduler.
  • 这里没有涉及JIT(不超过平时).编译器是将异步方法转换为状态机的编译器.您可以通过此TryRoslyn示例看到它.
  • 确实,async-await并不一定意味着并发,因为它可能是单线程的.但是,即使只有一个线程,通过同时启动和等待多个异步操作,它仍然可以并发.
  • async-await和TPL不是完全独立的部分.async-await建立在TPL之上.这就是为什么它被称为基于任务的异步模式.
  • 虽然大多数真正的异步操作都是I/O,但并非所有操作都是.您通常也会异步延迟Task.Delay或使用异步同步结构SemaphoreSlim.WaitAsync.

  • @w.brian 单个线程的并发性处于 I/O 硬件级别 - 单个线程可以启动(并等待)多个 I/O 操作,而在同步模式下,它必须等待(同时阻塞)每个一个结束,然后才能启动下一个。 (2认同)