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

时间:2015-08-08 23:00:35

标签: .net async-await task-parallel-library

我已经断言我对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线程之外执行。

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

滥用

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

1 个答案:

答案 0 :(得分:13)

这非常正确。

虽然有几点说明:

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