我有一个 .NET Windows 服务,它使用 BeginRead/EndRead 异步 I/O 范例实现套接字服务器。现在这个套接字代码需要调用一些 async/Task/await 异步代码。
我一直在使用 Nito.AsyncEx 库的 AsyncContext 类的 Run 方法,但我对从 EndRead 调用该方法是否会阻塞并劫持工作线程持有保留意见。我得到的建议my earlier question是使用 Task.Run 而不是 Nito.AsyncEx 的 AsyncContext.Run。这会将调用提交到 async/await 代码并立即返回。我突然想到,在负载下,客户端没有任何回退来防止请求淹没线程池。
我将重新问我原来关于 Nito.AsyncEx 的 AsyncContext.Run 的问题:它是否持有它调用的线程(调用我的套接字的 EndRead 回调的池线程)人质,或者它是否在异步时释放该线程它正在调用的 I/O 在后台发生?
如果 Nito.AsyncEx 的 AsyncContext.Run 真的阻塞,那么 Task.Run 似乎是我唯一的选择。关于如何推迟客户端请求以防止线程池耗尽的任何建议?
最佳答案
AsyncContext.Run
的目的是阻塞,直到所有异步操作完成。它确实会保持线程直到发生这种情况。
我建议您重新考虑目前的每一个假设:
- 你真的需要套接字服务器吗?围绕 TCP/IP 套接字存在大量的陷阱。严重地。 很多。有什么方法可以让您自行托管 WebAPI 吗?它比套接字服务器更容易开始工作。
- 为什么需要将工作推到线程池线程上?
End*
回调已在线程池线程上调用。 - 你确定你需要节流吗?没有代码可以阻止动机充分的 DoS 攻击。
如果您确定确实需要实现自己的 TCP/IP 服务器,并且无法在回调中同步完成工作,并且确实需要节流……那么请考虑 Reactive Extensions或 TPL Dataflow .这两个库都内置了可选的节流功能。
关于.net - 当你使用 Task.Run 太多以至于线程池耗尽时会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21340273/