异步等待和线程

基于我在MSDN上阅读的内容

async和await关键字不会导致创建其他线程。 异步方法不需要multithreading,因为异步方法不能在自己的线程上运行。 该方法在当前同步上下文上运行,并且仅在方法处于活动状态时才在线程上使用时间。 您可以使用Task.Run将CPU绑定的工作移动到后台线程,但后台线程无法帮助只等待结果可用的进程。

它基本上是说不会创建任何线程。 但是在我inheritance了HttpClient的类中,我发现了一些有趣的东西..

 async Task SendAsync(HttpMethod method, Uri uri, HttpContent content, CancellationToken cancellationToken) { HttpRequestMessage msg = new HttpRequestMessage(method, uri); msg.Content = content; //On Main Thread HttpResponseMessage response = await SendAsync(msg, cancellationToken); //On worker thread //... } 

该方法在static void Main调用

 Task result = client.GetAsync(...); //GetAsync calls await SendAsync result.Wait(); 

await SendAsnc调用后,为什么我在一个单独的线程? 我认为asyn没有新的主题。 或者至少在等待之后它将被调用回原始线程。

这在文档中很少公布,但是由于控制台应用程序中缺少同步上下文,async / await在控制台应用程序中的工作方式与在UI应用程序中的工作方式非常不同。 本文将介绍详细信息,并提供一个代码示例,说明如何添加一个以使async / await以更可预测的方式运行。

通常,你绝对正确的async / await 不一定需要multithreading(尽管像Task.Run 这样的事实上会导致有问题的代码在线程池中运行),但是(如我在链接到的文章中所述) )在控制台应用程序中,async / await可以在任何地方运行。

我在通常在同一个线程上运行时如何工作的通常类比是想到去一家餐馆和另外9个人(总共10个人)。 当服务员来的时候,有9个人准备好了,而第10个人没有准备好。 在这种情况下,服务员将首先接受其他9个人的命令,然后再回到第10个人。 如果由于某种原因,第10个人的速度非常慢,服务员总是可以将订单带回厨房,并在第10个人准备就绪时回来。

显然,没有必要引进第二个服务员只是为了等待第10个人准备好订购,并且让其他人等待一个人做好准备显然效率低下。 添加额外的服务员不会加速,因为延迟不是由于缺乏服务员造成的,这是由于第10个人慢慢下定决心(而且等待人员无法做到这一点) )。

我在async博客文章的介绍中描述了这种行为。

总之,这是正确的:

async和await关键字不会导致创建其他线程。

这是这样的:

我认为asyn没有新的主题。

正确:

或者至少在等待之后它将被调用回原始线程。

asyncawait它们自己 – 不会导致创建任何其他线程。 但是,在await完成之后, async方法的其余部分必须在某处运行。

默认情况下, await捕获“context”,它是当前的SynchronizationContext (除非它为null ,在这种情况下,当前上下文是当前的TaskScheduler )。 UI线程有自己的同步上下文(例如, WinFormsSynchronizationContextDispatcherSynchronizationContext ),在这种情况下, async方法将继续在同一UI线程上执行。

在控制台应用程序中,没有同步上下文,因此await捕获的“上下文”将是线程池上下文。 因此,当async方法准备好恢复时,它将被调度到线程池并由那里的某个线程拾取。

控制台应用程序有一个线程池SynchronizationContext,而不是GUI和ASP.Net应用程序中使用的一次一块的SynchronizationContext,因此当await完成时,它会在线程池线程上调度async方法的其余部分。 。 阅读本文以获取有关异步等待行为的更多信息。