如何在 Semaphore 和 SemaphoreSlim 之间进行选择?

他们的公共界面看起来很相似。文件声明 SemaphoreSlim 是一个轻量级的替代品,并且不使用 Windows 内核信号量。这个资源指出 SemaphoreSlim 要快得多。在什么情况下,SemaphoreSlim 比 Semaphore 更有意义,反之亦然?

29880 次浏览

一个区别是 SemaphoreSlim不允许命名信号量,这可以是系统范围的。这意味着 SemaphoreSlim 不能用于跨进程同步。

MSDN 文档 还指出,当“预计等待时间非常短”时,应该使用 SemSlim。这通常会很好地吻合这样的想法,即对于大多数权衡来说,苗条版本更轻量级。

MSDN 文档 描述了这种差异。

一句话:

  • SemaphoreSlim 类表示一个轻量级、快速的信号量,当等待时间预计非常短时,可以在单个进程中使用该信号量进行等待。

关于“短期”的争议:

至少 SemaphoreSlim MSDN 文档是这么说的

SemaphoreSlim 类是单个应用程序内同步的推荐信号量。

同样的部分也讲述了 Semaphore 和 SemaphoreSlim 的主要区别:

SemaphoreSlim 是不使用 Windows 内核信号量的 Semaphore 类的轻量级替代品。与 Semaphore 类不同,SemaphoreSlim 类不支持命名的系统信号量。只能将其用作本地信号量。

SemaphoreSlim 基于 SpinWait 和 Monitor,因此等待获取锁的线程会消耗 CPU 周期一段时间,希望在向另一个线程屈服之前获取锁。如果没有发生这种情况,那么线程将允许系统切换上下文,并在操作系统再次调度该线程时再次尝试(通过消耗一些 CPU 周期)。经过长时间的等待,这种模式可能会耗费大量的 CPU 周期。因此,这种实现的最佳情况是,大多数时候没有等待时间,您几乎可以立即获得锁。

信号量依赖于操作系统内核中的实现,因此每次获取锁时,都会花费相当多的 CPU 周期,但在此之后,线程只需要睡眠足够长的时间就可以获取锁。

我查看了源代码 给你,得出了以下结论:

  1. Semaphore 和 SemaphoreSlim 都使用 WaitHandle,WaitHandle 在内部使用 Win32本机句柄。这就是为什么您需要处理()两者。因此,斯利姆是轻量级的观点是可疑的。

  2. SemaphoreSlim 在内部使用 SpinWait,而 Semaphore 不使用。这告诉我,在等待时间很长的情况下,Semaphore 应该做得更好,至少在不会阻塞 CPU 的意义上。