.net - 等待异步模式和工作窃取线程

标签 .net multithreading asynchronous

我正在尝试了解异步/等待模式的底层机制,我想我在阅读了以下优秀文章后得到了它 Work-Stealing in .NET 4.0作者:詹妮弗·马斯曼。我的理解是

1 - 有线程池的全局队列,以及线程池中每个线程的本地队列

2 - 请求进来,在全局队列中,然后线程池中的 thread1 (T1) 抓取该请求。

3 - 此请求是 async\await 方法。一旦点击了await关键字,就会创建一个包裹在任务中的书签(回调)(假定任务未完成),并且该任务被放置在T1的本地队列中。 T1返回池中

4 - 当任务完成时,如果 T1 不忙,T1 将处理该请求。但如果 T1 很忙,另一个线程(称为 T2)实际上可能会从 T1 的本地队列中窃取此任务

这就是我的问题所在。这是如何禁止的?我读到的所有内容都表明 async\await 不会更改线程上下文。请参阅链接MSDN explanation of async\await这也是有道理的,因为在 MVC 应用程序中,请求绑定(bind)到线程。这意味着,如果请求到达异步操作方法,我希望初始任务和延续任务都由同一个线程池线程完成。工作窃取线程如何不干扰这一点?感谢任何见解。

最佳答案

这里有三个半独立的系统在工作:线程池(带有工作窃取队列)、ASP.NET 请求上下文和 async/await .

线程池的工作方式如您所描述的:每个线程都有自己的队列,但如果需要,可以从其他线程的队列中窃取。但这实际上与 async/await 在 ASP.NET 上的工作方式关系不大。在大多数情况下,您可以完全忽略工作窃取队列的工作原理,因为逻辑抽象是具有单个队列的单个线程池。工作窃取队列只是一种优化。

ASP.NET 请求上下文管理诸如 HttpContext.Current、安全性和文化等内容。它不绑定(bind)到特定线程,但上下文中一次只允许一个线程。此模式对于旧式异步请求和新式async 请求均适用。请注意,请求从头到尾都绑定(bind)到一个线程仅适用于同步请求;对于异步请求来说,这是的情况(而且从来都不是)。 ASP.NET 请求上下文被实现为同步上下文 - 具体来说,是 AspNetSynchronizationContext 的实例。

当您的代码 await 是一个不完整的 Task 时,默认情况下 await 将捕获当前上下文(即 SynchronizationContext.Current 除非它是 null,在这种情况下它是当前的 TaskScheduler)。当Task完成时,async方法将在该上下文中继续。我更详细地描述了这种行为on my blog 。您可以将 async/await 视为“线程无关”;也就是说,它们不一定在不同的线程上恢复,也不一定在同一线程上恢复。他们将所有线程决策留给捕获的上下文。

另一个旁注是,有两种不同类型的任务,Promise 任务和委托(delegate)任务(正如我所描述的 on my blog )。只有委托(delegate)任务实际上有代码要运行,并且根本不会排队到线程池中。因此,当 await 决定挂起其方法时,它没有代码要运行,并且当时没有任何代码排队;相反,它设置一个回调(延续),将方法的其余部分在将来排队。

当等待的任务完成时,回调/延续将运行,它将 async 方法的剩余部分排队到捕获的上下文。理论上,这可以将其排队到线程池中,但实际上有一个几乎总是采取的捷径:完成任务的线程通常是线程池线程本身,因此它只是直接进入请求上下文,然后继续执行async 方法,实际上不必在任何地方排队。

因此在绝大多数情况下,工作窃取队列根本不会发挥作用。它实际上只在线程池工作重载时才会发生。

但请注意,完全有可能(并且很常见)让异步处理程序在一个线程上启动并在另一个线程上继续。这通常不是问题,因为请求上下文被保留,但线程局部变量等线程仿射结构将无法正常工作。

关于.net - 等待异步模式和工作窃取线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25193438/

相关文章:

java - Jmeter行为怪癖

node.js - 如何异步执行多个 Nightmare 函数

javascript - 如何使用 for 循环并使用 Node 返回结果?

c# - JSON Web Token 有效性验证在 .NET Core 上通过但在 .NET 4.6.1 上失败

c# - ASP.NET 站点 - 在特定时间触发一些代码

model-view-controller - 线程安全的 Controller 和实用程序类?

javascript - 仅当唯一时使用 knex 插入

c# - 我如何使用 WCF 数据服务?

.net - 在未安装 Visual Studio 的情况下在 TeamCity 构建服务器上运行 MSTest

multithreading - “threadgroup_barrier”没有区别