异步等待和线程

Ste*_*eve 5 c# async-await

基于我在MSDN上阅读的内容

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

它基本上是说不会创建任何线程.但在我继承的一个班级里面,HttpClient我发现了一些有趣的东西......

async Task<T> SendAsync<T>(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
        //...
}
Run Code Online (Sandbox Code Playgroud)

这个方法在里面调用 static void Main

Task result = client.GetAsync<string>(...);
//GetAsync calls await SendAsync<T>
result.Wait();
Run Code Online (Sandbox Code Playgroud)

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

EJo*_*ica 12

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

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

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

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


Ste*_*ary 9

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

总之,这是正确的:

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

这是这样的:

我认为asyn没有新的主题.

正确:

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

async并且await- 本身 - 不会导致创建任何其他线程.但是,await完成后,async方法的其余部分必须在某处运行.

默认情况下,await捕获"上下文",这是当前的SynchronizationContext(除非是null,在这种情况下,当前上下文是当前上下文TaskScheduler).UI线程具有其自己的同步上下文(例如,WinFormsSynchronizationContextDispatcherSynchronizationContext),并且在该情况下,该async方法将在该相同的UI线程上继续执行.

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