Як вибрати між Semaphore та SemaphoreSlim?


109

Їх публічний інтерфейс виглядає схожим. У документації зазначено, що SemaphoreSlim є легкою альтернативою і не використовує семафори Windows Kernel. Цей ресурс зазначає, що SemaphoreSlim набагато швидше. У яких ситуаціях SemaphoreSlim має більше сенсу над Семафором і навпаки?


1
Семафор завжди передає завдання в ОС. Це робить його відносно дорогим, якщо семафор сильно не оскаржується, виклик ядра легко коштує 400 наносекунд. Тонка послуга спочатку намагається зробити це дешево за допомогою загальної змінної, лише зателефонувавши в ОС, коли це не вийшло. Вам завжди подобається дешеве, за винятком випадків, коли семафор повинен ділитися декількома процесами.
Ганс Пасант

Відповіді:


64

Одна відмінність полягає в тому, що SemaphoreSlimвони не дозволяють називати семафори, які можуть бути загальносистемними. Це означатиме, що SemaphoreSlim не можна використовувати для міжпроцесової синхронізації.

Документація MSDN також вказує, що SemSlim слід використовувати, коли "очікується, що час очікування буде дуже коротким". Зазвичай це добре підходить для думки про те, що струнка версія більш легка для більшості компромісів.


66
Я б хотів, щоб МС написала щось про те, що відбувається, коли терміни очікування не є "дуже короткими".
Джон Рейнольдс

79
... або що означає "дуже короткий"
Річард Шалай

9
Залежно від системи, 1 мікросекунда для Semaphore і 1/4 мікросекунди для SemaphoreSlim, щоб зробити WaitOne або Release ["C # 5.0 в горішці", стор. 890] То, може, саме це розуміють під дуже короткими термінами очікування?
Девід Шеррет

2
@dhsto Хороша довідка! Але я здогадуюсь, що пов'язана стаття означає "коли час очікування для доступу до спільного ресурсу дуже короткий" - тобто ресурс не залишатиметься в ексклюзивному використанні протягом тривалого періоду часу, - а не означає терміни очікування самого коду семафору? Код семафору завжди буде виконуватися незалежно від того, як довго ресурс буде заблокований.
culix

4
@culix Дивлячись на джерело для Semaphore проти SemaphoreSlim, я підозрюю, що головна причина того, що SemaphoreSlim слід використовувати лише для "дуже коротких" очікувань, це тому, що він використовує спінне очікування. Це більш чутливо, але з'їдає багато процесора і буде марно витрачати довші періоди очікування, коли миттєві відповіді менш важливі. Семафор замість цього блокує нитку.
r2_118

17

Документація MSDN описує різницю.

В одному реченні:

  • Клас SemaphoreSlim являє собою легкий, швидкий семафор, який можна використовувати для очікування в рамках одного процесу, коли очікується, що час очікування буде дуже коротким.

1
Щоб додати це, використовуйте SemaphoreSlim у всіх випадках, коли ваша програма є єдиним процесом на вашому комп’ютері, який потребує доступу до цього Semaphore.
Остін Салгат

2
@Salgat Навіщо ти це робив? Як викладено в інших відповідях, SemaphoreSlimреалізується за допомогою SpinWait, тому якщо ви будете багато чекати, ви витратите багато часу на процесор. Що навіть не гарна ідея, якщо ваш процес - єдиний процес на комп’ютері.
М.Страмм

З документації MSDN "Клас SemaphoreSlim є рекомендованим семафором для синхронізації в одному додатку." За винятком особливих випадків, вам слід використовувати за замовчуванням використання SemaphoreSlim, якщо лише один процес використовує цей семафор. Спеціальні винятки зазвичай існують для будь-якого одночасного типу даних, що само собою зрозуміло.
Остін Салгат

17

SemaphoreSlim заснований на SpinWait і Monitor, тому потік, який чекає придбання блокування, певний час записує цикли процесора, сподіваючись придбати замок, перш ніж перейти до іншого потоку. Якщо цього не відбувається, то потоки дозволяють системам перемикати контекст і намагаються знову (спалюючи деякі цикли процесора), як тільки ОС знову планує цю нитку. Якщо довго чекати, ця модель може прогоріти через значну кількість циклів процесора. Тож найкращий сценарій для такої реалізації - це тоді, коли більшість часу немає часу очікування і ви можете майже миттєво придбати замок.

Semaphore покладається на реалізацію в ядрі ОС, тому кожен раз, коли ви придбаєте замок, ви витрачаєте досить багато процесорних циклів, але після цього потік просто спить стільки, скільки потрібно, щоб отримати замок.


12

Щодо полеміки "короткий час":

Принаймні документація SemaphoreSlim MSDN стверджує, що

Клас SemaphoreSlim - це рекомендований семафор для синхронізації в одному додатку.

у розділі «Зауваження». У цьому ж розділі також вказана основна відмінність між Semaphore і SemaphoreSlim:

SemaphoreSlim - це легка альтернатива класу Semaphore, який не використовує семафори ядра Windows. На відміну від класу Semaphore, клас SemaphoreSlim не підтримує названі системні семафори. Ви можете використовувати його лише як локальний семафор.


1
Докладніше [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:: dotnet.github.io/docs/essentials/collections/…
Марко Сулла,

0

Я подивився на вихідний код тут , і це те , що я придумав:

  1. І Semaphore, і SemaphoreSlim походять від WaitHandle, який внутрішньо використовує вбудовану ручку Win32. Саме тому вам потрібно розпоряджатися () обома. Тож уявлення про те, що Slim є легким, є підозрюваним.

  2. SemaphoreSlim використовує SpinWait внутрішньо, а Semaphore - ні. Це говорить мені про те, що у випадках, коли очікується, що очікування буде тривалим, Semaphore повинен робити краще, принаймні в тому сенсі, що він не задушить ваш процесор.


2
SemaphoreSlim не походить від WaitHandle. Насправді він був створений з єдиною метою - усунути похідне від WaitHandle, що є простором ядра, примітивним, у завданнях, де потрібно синхронізувати операції всередині одного процесу.
Ігор V Савченко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.