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


109

它们的公共接口看起来相似。该文档指出,SemaphoreSlim是一种轻量级替代方案,并且不使用Windows Kernel信号灯。 此资源表明SemaphoreSlim更快。在什么情况下,SemaphoreSlim比Semaphore更有意义,反之亦然?


1
信号量始终将作业传递给OS。如果信号灯的争用不强,则这相对昂贵,内核调用很容易花费400纳秒。苗条的支持首先尝试使用共享变量廉价地完成此操作,仅在不起作用时才调用OS。您总是喜欢便宜的东西,除非在极少数情况下信号量需要由多个进程共享。
汉斯·帕桑

Answers:


64

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

MSDN文档还指出,当“等待时间预计非常短”时,应使用SemSlim。通常,在大多数折衷方案中,细长型版本的重量更轻,这通常可以很好地与之吻合。


66
我希望MS写一些有关等待时间不是很短时会发生什么的事情。
约翰·雷诺兹

79
...或“非常简短”的意思
理查德·萨雷

9
取决于系统,Semaphore用1微秒,SemaphoreSlim用1/4微秒来执行WaitOne或Release [“ Cut 5.0 in a Nutshell” pg。[890]因此,也许这就是很短的等待时间的意思?
David Sherret

2
@dhsto很好的参考!但是我猜链接文章的意思是“当访问共享资源的等待时间非常短时”(即资源将不会长时间长时间独占使用)而不是意味着信号量代码本身的等待时间?无论资源被锁定多长时间,信号灯代码将始终执行。
culix

4
@culix查看Semaphore与SemaphoreSlim的来源我怀疑SemaphoreSlim仅应用于“非常短”的等待的主要原因是因为它使用了旋转等待。这种方法响应速度更快,但是会占用大量CPU,并且在瞬时响应不太重要的较长等待时间内会浪费很多时间。信号量会阻塞线程。
r2_118 '16

17

MSDN文档描述了差异。

一句话:

  • SemaphoreSlim类表示轻量级的快速信号量,当预期等待时间非常短时,可用于在单个进程中等待。

1
为此,在所有应用程序是计算机上唯一需要访问该信号量的进程的情况下,请使用SemaphoreSlim。
奥斯丁·萨尔加特

2
@Salgat为什么要这么做?正如其他答案中概述的那样,它SemaphoreSlim是使用SpinWait实现的,因此,如果您等待很多,则会浪费大量CPU时间。如果您的进程是计算机上唯一的进程,那甚至不是一个好主意。
M.Stramm '16

从MSDN文档中,“ SemaphoreSlim类是建议在单个应用程序内进行同步的信号灯。” 除特殊情况外,如果只有一个进程正在使用该信号量,则应默认使用SemaphoreSlim。对于任何并发数据类型,通常都存在特殊的例外,这毋庸置疑。
奥斯丁·萨尔加特

17

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

Semaphore依赖于OS内核中的实现,因此,每次获取锁时,您都会花费大量的CPU周期,但是此后,线程只是为了获得锁而睡眠了必要的时间。


12

关于“短时间”争议:

至少SemaphoreSlim MSDN文档指出:

SemaphoreSlim类是建议在单个应用程序内进行同步的信号量。

在备注部分。同一部分还说明了Semaphore和SemaphoreSlim之间的主要区别:

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


1
更多详细信息::dotnet.github.io/docs/essentials/collections/…–[SemaphoreSlim and other locks] use busy spinning for brief periods before they put the thread into a true Wait state. When wait times are expected to be very short, spinning is far less computationally expensive than waiting, which involves an expensive kernel transition
Marco Sulla,

0

我在这里查看了源代码,这是我想到的:

  1. Semaphore和SemaphoreSlim都源自内部使用Win32本机句柄的WaitHandle。这就是为什么您都需要同时Dispose()的原因。因此,Slim是轻量级的概念值得怀疑。

  2. SemaphoreSlim内部使用SpinWait,而Semaphore不使用。这告诉我,在预期等待时间较长的情况下,Semaphore至少应在不停止CPU的意义上做得更好。


2
SemaphoreSlim不是从WaitHandle派生的。实际上,它的创建是有一个目标的-在需要仅同步一个进程内的任务的任务中,消除源于内核空间原语的WaitHandle的派生。
Igor V Savchenko
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.