c# - Task.Delay 是否真正像 I/O 操作那样异步,即它是否依赖于硬件和中断而不是线程?

标签 c# .net asynchronous task delay

我发现了大量的相关内容,但我一直找不到答案。我几乎 100% 肯定 Task.Delay(int) 不使用线程,因为我可以在我的机器上运行这个代码只有 16 个逻辑处理器:

var tasks = new List<Task>();
for(int i = 1; i < 100000; i++) tasks.Add(Task.Delay(10000));
await Task.WhenAll(tasks);

而且需要十秒钟才能完成。我认为,如果它使用大约十万个线程,则需要更长的时间。

所以我的问题是Task.Delay(int) 是如何工作的? 不是以this poorly-entitled SO question 的方式指示,但从线程和硬件资源的角度来看。

最佳答案

在当前的 .NET 实现中,有一个“计时器线程”仅跟踪托管计时器实例并在适当的时间引发它们的事件。此计时器线程将 block在其控制信号上将超时设置为下一个计时器的到期时间。控制信号用于添加/删除/更改计时器,因此当此阻塞请求超时时,计时器线程知道下一个计时器已触发。这是一个正常的线程阻塞操作,因此在内部,线程处于空闲状态并从调度程序队列中删除,直到该阻塞操作完成或超时。这些操作的超时由操作系统调度程序的定时器中断处理。

所以从技术上讲有一个线程,但每个进程只有一个线程,而不是每个 Task.Delay 一个线程。

我再次强调这是在 .NET 的当前实现中。已经提出了其他解决方案,例如每个 CPU 一个计时器线程,或计时器线程的动态池。也许他们因为某种原因被试验并被拒绝,或者将来可能会采用替代解决方案。据我所知,这在任何地方都没有正式记录,所以这是一个实现细节。

关于c# - Task.Delay 是否真正像 I/O 操作那样异步,即它是否依赖于硬件和中断而不是线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65219573/

相关文章:

c# - 使用语法糖/内置功能

.net - 如何通过 Tor 发出 httpwebrequest

javascript - 异步 JavaScript 最佳实践

javascript - 为什么 promise 会解决?

c# - 使用 DataGridView.SelectedRows 作为另一个 DataGridView 的数据源

c# - 在 .Net 2.0 的 64 位应用程序中使用 32 位 DLL

c# - 处理未知数量的捕获组时仅替换一组

c# - 修改注册表中的环境变量

.net - 对于只读 xml 数据库来说,嵌入资源是一个好方法吗?

c++ - 与 std::future 关联的存储是如何分配的?