Comment choisir entre Semaphore et SemaphoreSlim?

109

Leurs interfaces publiques semblent similaires. La documentation indique que SemaphoreSlim est une alternative légère et n'utilise pas de sémaphores du noyau Windows. Cette ressource indique que le SemaphoreSlim est beaucoup plus rapide. Dans quelles situations le SemaphoreSlim a-t-il plus de sens sur le Sémaphore et vice versa?

Michael Hedgpeth
la source
1
Semaphore transmet toujours le travail au système d'exploitation. Cela rend relativement coûteux si le sémaphore n'est pas fortement contesté, l'appel du noyau coûte facilement 400 nanosecondes. La faveur mince essaie d'abord de le faire à moindre coût avec une variable partagée, n'appelle que dans le système d'exploitation lorsque cela ne fonctionne pas. Vous aimez toujours bon marché, sauf dans le cas du coin où le sémaphore doit être partagé par plusieurs processus.
Hans Passant

Réponses:

64

Une différence est que cela SemaphoreSlimn'autorise pas les sémaphores nommés, qui peuvent être à l'échelle du système. Cela signifierait qu'un SemaphoreSlim ne pourrait pas être utilisé pour la synchronisation inter-processus.

La documentation MSDN indique également que SemSlim doit être utilisé lorsque «les temps d'attente sont censés être très courts». Cela cadrerait généralement bien avec l'idée que la version mince est plus légère pour la plupart des compromis.

Andrew Barber
la source
66
J'aurais aimé que MS ait écrit quelque chose sur ce qui se passe lorsque les temps d'attente ne sont pas «très courts».
John Reynolds
79
... ou ce que signifie «très court»
Richard Szalay
9
Selon le système, 1 microseconde pour Semaphore et 1/4 microseconde pour SemaphoreSlim pour faire un WaitOne ou Release ["C # 5.0 en bref" pg. 890] C'est peut-être ce qu'ils veulent dire par des temps d'attente très courts?
David Sherret
2
@dhsto Bonne référence! Mais je suppose que l'article lié signifie "quand les temps d'attente pour accéder à la ressource partagée sont très courts" - c'est-à-dire que la ressource ne restera pas en usage exclusif pendant de longues périodes - plutôt que de signifier les temps d'attente pour le code du sémaphore lui-même? Le code du sémaphore s'exécutera toujours quelle que soit la durée pendant laquelle la ressource est maintenue verrouillée.
culix
4
@culix En regardant la source de Semaphore par rapport à SemaphoreSlim, je soupçonne que la principale raison pour laquelle SemaphoreSlim ne devrait être utilisé que pour des attentes "très courtes" est qu'il utilise une attente de rotation. C'est plus réactif, mais consomme beaucoup de CPU et serait un gaspillage pour des périodes d'attente plus longues où les réponses instantanées sont moins importantes. Semaphore bloque le thread à la place.
r2_118
17

La documentation MSDN décrit la différence.

En une phrase:

  • La classe SemaphoreSlim représente un sémaphore léger et rapide qui peut être utilisé pour l'attente dans un processus unique lorsque les temps d'attente devraient être très courts.
Joe
la source
1
Pour ajouter à cela, utilisez SemaphoreSlim dans tous les cas où votre application est le seul processus de votre ordinateur qui aura besoin d'accéder à ce sémaphore.
Austin Salgat
2
@Salgat Pourquoi feriez-vous ça? Comme indiqué dans d'autres réponses, SemaphoreSlimest implémenté à l'aide de SpinWait, donc si vous attendez beaucoup, vous perdrez beaucoup de temps CPU. Ce n'est même pas une bonne idée si votre processus est le seul processus sur l'ordinateur.
M.Stramm
Dans la documentation MSDN, «La classe SemaphoreSlim est le sémaphore recommandé pour la synchronisation dans une seule application». Sauf dans des cas particuliers, vous devez utiliser par défaut SemaphoreSlim si un seul processus utilise ce sémaphore. Des exceptions spéciales existent généralement pour tout type de données concurrentes, ce qui va sans dire.
Austin Salgat
17

SemaphoreSlim est basé sur SpinWait et Monitor, donc le thread qui attend d'acquérir le verrou brûle des cycles CPU pendant un certain temps dans l'espoir d'acquérir le verrou avant de céder à un autre thread. Si cela ne se produit pas, les threads permettent aux systèmes de changer de contexte et essaient à nouveau (en brûlant certains cycles de processeur) une fois que le système d'exploitation planifie à nouveau ce thread. Avec de longues attentes, ce modèle peut brûler une quantité substantielle de cycles CPU. Le meilleur scénario pour une telle implémentation est donc lorsque la plupart du temps, il n'y a pas de temps d'attente et que vous pouvez acquérir presque instantanément le verrou.

Semaphore repose sur l'implémentation dans le noyau du système d'exploitation, donc chaque fois que vous acquérez le verrou, vous passez pas mal de cycles CPU, mais après cela, le thread dort simplement aussi longtemps que nécessaire pour obtenir le verrou.

Dmytro Zakharov
la source
12

Concernant la controverse sur les «temps courts»:

Au moins la documentation de SemaphoreSlim MSDN indique que

La classe SemaphoreSlim est le sémaphore recommandé pour la synchronisation dans une seule application.

dans la section Remarques. La même section indique également la principale différence entre Semaphore et SemaphoreSlim:

Le SemaphoreSlim est une alternative légère à la classe Semaphore qui n'utilise pas de sémaphores du noyau Windows. Contrairement à la classe Semaphore, la classe SemaphoreSlim ne prend pas en charge les sémaphores système nommés. Vous pouvez l'utiliser uniquement comme sémaphore local.

Shaedar
la source
1
Plus de détails: [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/...
Marco Sulla
0

J'ai regardé le code source ici et c'est ce que j'ai trouvé:

  1. Semaphore et SemaphoreSlim dérivent de WaitHandle qui utilise en interne le handle natif Win32. C'est pourquoi vous devez utiliser Dispose () à la fois. Donc, l'idée que Slim est léger est suspecte.

  2. SemaphoreSlim utilise SpinWait en interne, contrairement à Semaphore. Cela me dit que dans les cas où l'attente devrait être longue, Semaphore devrait faire mieux au moins dans le sens où il n'étouffera pas votre CPU.

ILIA BROUDNO
la source
2
SemaphoreSlim n'est pas dérivé de WaitHandle. En fait, il a été créé avec un seul objectif: éliminer les dérivations de WaitHandle, qui est une primitive d'espace noyau, dans les tâches où vous devez synchroniser les opérations dans un seul processus.
Igor V Savchenko