ManualResetEventSlim 在短等待(通常
在绝大多数短等待(ManualResetEventSlim 的吞吐量可比 ManualResetEvent 高 3–10 倍;但一旦等待时间超过几毫秒,两者性能差距迅速收窄,甚至反超——因为 ManualResetEventSlim 会自动退化为内部调用 ManualResetEvent(即“自旋 + 落地”策略)。这不是 bug,是设计使然。
ManualResetEventSlim 优先自旋(busy-wait),避免线程挂起/唤醒的调度开销ManualResetEventSlim 在自旋一定次数(默认 ~10 微秒或 10 次循环)后,会 fallback 到内核事件等待,此时性能 ≈ ManualResetEvent
ManualResetEventSlim 仅限单进程内使用;ManualResetEvent 可通过 EventWaitHandle 底层支持命名句柄,实现跨进程同步选它,不是因为它“更现代”,而是你明确知道:等待时间极短、线程数可控、且不需要跨进程能力。
WaitOne(),ManualResetEventSlim 的自旋可能抬高 CPU 使用率——这不是卡死,是设计代价完全一致。两者都遵循 Manual Reset 语义:一次 Set() 可唤醒所有等待线程,且信号持续有效,直到显式调用 Reset()。
new ManualResetEvent(false) 和 new ManualResetEventSlim(false) 初始化效果相同:首次 WaitOne() 阻塞new ManualResetEvent(true) 和 new ManualResetEventSlim(true) 同样跳过首次等待ManualResetEvent 替换
为 ManualResetEventSlim,只要不依赖跨进程或长期阻塞static void ExampleUsage()
{
var mres = new ManualResetEventSlim(false);
var t = new Thread(() =>
{
Console.WriteLine("Thread waiting...");
mres.WaitOne(); // 短等待 → 自旋;长等待 → 落地为内核等待
Console.WriteLine("Thread resumed.");
});
t.Start();
Thread.Sleep(10);
mres.Set(); // 唤醒
t.Join();
}
真正容易忽略的点是:别为了“听起来更轻量”而盲目替换。如果你的 WaitOne() 平均耗时 > 5ms,或者压根没测过等待分布,那 ManualResetEventSlim 可能只是多了一层不必要的自旋开销,还失去调试可见性(比如无法用 Windows 性能分析器直接看到命名事件句柄)。性能优化,永远从测量开始,而不是从类名开始。