我一直在阅读有关 async/await 与 ThreadPool 与 Threads 的一些内容,我不得不承认,我对细节并不完全清楚。有一个具体问题我想我有答案,但我不能肯定地说。
我也知道关于 SO 和其他地方的许多问题,这些问题正在被讨论和解释。我在这里阅读了一些关于 SO 的内容,但我还没有找到明确的答案,或者至少没有我想要的那么清楚。
我收集到的:
然而,一位同事是这样说的:
所以,我想问的是:
请注意,我不是在讨论客户端的事情,只是从服务器的角度来看。
如果我错过了对此的确切答案,请提前抱歉,我已经看过了 =)
最佳答案
真正的问题不是“线程池与 async
/await
”,而是同步 I/O 与异步 I/O。 [1]
在 Windows 上,线程是相对昂贵的对象——一个线程有很多与之相关的操作系统簿记,更不用说 1 MB 的预分配堆栈空间。这对系统甚至支持的线程数量设置了相当低的上限,即使您没有达到该上限,所有这些线程之间的上下文切换也不便宜。 “32,000 个线程”的限制是一个严格的理论限制,并且非常看好您可以拥有多少线程并且仍然可以响应! [2]
进入异步 I/O,它被优化为仅使用尽可能多的线程(通常是系统中物理处理器内核数量的一些保守倍数),理想情况下甚至不创建超出初始批处理的新线程。这些线程专用于处理已完成的 I/O 操作,方法是将它们从队列(称为完成端口)中移除。当异步操作正在进行时,根本没有线程专用于它,甚至没有作为等待列表中的项目(Stephen Cleary 有一个很好的 blog post 对此进行了更详细的解释)。思考什么更有效不需要太多想象力:
事实证明,后者的扩展性比前者好得多;即使在您使用线程池来减少新线程的创建时,在原始服务器代码中常见的“每个请求的线程”模型也很快显示出其局限性。请注意,这是一个早在
async
之前的问题。/await
曾经是一回事,Windows 所采用的解决方案也是如此; async
/await
只是一种使用现有机制编写代码的新方法。您是否可能会注意到一次只有少数几个请求的差异?没有。但是因为
async
/await
本质上允许您编写看起来同步但具有“免费”异步 I/O 可扩展性的代码,为什么不选择使用它来支持排队到线程池的同步 I/O?[1] 事实证明斯蒂芬·克利里已经 wrote most of what's in this answer几年前。我建议你也读一下。
[2] 这是一个 older post作者:Mark Russinovich,他实际上试图从系统中挤出尽可能多的线程——只是为了好玩和盈利。在所有资源都消失之前,他“只”在 64 位机器上达到 55K,这就是调整默认堆栈大小,而没有做任何实际有用的工作。在现代系统上,您可能会得到更多,但真正的问题不应该是“我可以拥有多少个线程”——如果是,那么您就做错了。
关于c# - ThreadPool 线程执行 I/O 操作 - 线程可以在等待时重用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56425062/