关于ThreadPool.RegisterWaitForSingleObject
,这不会占用每个注册的线程(池化或其他)。您可以轻松地对此进行测试:在 LINQPad 中运行以下脚本,该脚本调用该方法 20,000 次:
static ManualResetEvent _starter = new ManualResetEvent (false);
void Main()
{
var regs = Enumerable.Range (0, 20000)
.Select (_ => ThreadPool.RegisterWaitForSingleObject (_starter, Go, "Some Data", -1, true))
.ToArray();
Thread.Sleep (5000);
Console.WriteLine ("Signaling worker...");
_starter.Set();
Console.ReadLine();
foreach (var reg in regs) reg.Unregister (_starter);
}
public static void Go (object data, bool timedOut)
{
Console.WriteLine ("Started - " + data);
// Perform task...
}
如果该代码在 5 秒的“等待”期间占用了 20,000 个线程,它就不可能工作。
编辑- 回应:
“这是一个证明。但是否还有一个线程只检查信号?在线程池中?”
这是一个实现细节。是的,它可以通过将回调卸载到托管线程池的单个线程来实现,尽管不能保证这一点。等待句柄最终由操作系统管理,这很可能也会触发回调。它可能在其内部实现中使用一个线程(或少量线程)。或者使用中断,它可能不会阻塞单个线程。它甚至可能因操作系统版本而异。这是一个与我们没有真正关系的实现细节。