7
votes

L'utilisation d'une serrure a-t-elle une meilleure performance que d'utiliser un sémaphore local (application unique)?

Utilise une serrure a de meilleures performances que d'utiliser un sémaphore local (application unique)?

J'ai lu ce blog de MSDN: Solution de consommateur producteur sur msdn

Et je n'ai pas aimé leur solution au problème car il y a toujours 20 éléments laissés dans la file d'attente.

Donc, à la place, j'ai pensé à utiliser un «sémaphore» qui sera disponible uniquement dans mon application (je ne le nommerai tout simplement pas dans le constructeur), mais je ne sais pas comment cela affectera la performance de l'application. < / p>

Quelqu'un a-t-il une idée si cela affectera la performance? Quelles sont les autres considérations pour utiliser un verrou et non «sémaphore»?


1 commentaires

Ceci est intégré à .NET 4.0 et fonctionne bien sur la boîte ..


5 Réponses :


10
votes

verrouillage (obj) est identique à moniteur.enter (obj); Un verrou est basicaly un sémaphore unaire. Si vous avez un certain nombre d'instances de la même ressource (n), vous utilisez un sémaphore avec la valeur d'initialisation N. Un verrouillage est principalement utilisé pour assurer qu'une section de code n'est pas exécutée par deux threads en même temps.

Donc, une serrure peut être mise en œuvre à l'aide d'un sémaphore avec une valeur d'initialisation de 1. Je suppose que mon moniteur.enter est plus performant ici, mais je n'ai aucune information réelle à ce sujet. Un test sera utile ici. Voici un SO Thread qui fait face à la performance.

Pour votre problème, une file d'attente de blocage serait la solution. (Consumer producteur) Je suggère Ce très bon alors fil.

Voici une autre bonne source d'informations sur structures de données parallèles réutilisables .


4 commentaires

Merci pour la réponse mais ça ne répond pas vraiment à ma question :)


J'ai ajouté un lien vers un autre sifflement qui gère la performance. Cela vous aide-t-il?


Remarque: un sémaphore (au niveau du système d'exploitation) utilise la serrure matérielle beaucoup plus rapide, de sorte que la mise en oeuvre d'un verrou à l'aide d'un sémaphore semble un peu contrapoductive.


La serrure est en fait différente de la sémaphore, compte tenu de la réentrancement: la serrure est réentrante, tandis que le sémaphore n'est pas. Le sémaphore peut toutefois être libéré dans d'autres fils.



1
votes

2 commentaires

Merci pour la réponse, mais votre message a un bogue différent .. La vérification du consommateur qui vérifie si la taille de la file d'attente n'est pas égale à zéro est problématique. Exemple: la file d'attente contient un produit. Deux clients font la vérification simultanément et entrez la boucle tandis que, on verrouille le moniteur et l'autre attend. Le premier consomme le produit (il n'y a donc plus de produits!), puis quitte le moniteur. Maintenant, le second pénètre dans le moniteur et essayez de déroger une file d'attente vide. Erreur fatale.


En fait, lorsque le second consommateur se réveille dans la boucle interne tandis que la boucle et réacquierez la serrure, il continuera de boucler et de vérifier si la file d'attente est vide avant de décider de continuer et de déroger de la file d'attente afin de ne pas obtenir l'erreur. Vous venez de mentionner. Toutefois, comme l'auteur a mentionné que ce n'est qu'une implémentation partielle et que cela ne fait rien avec l'élément de déséquilibre.



2
votes

En général: Si votre thread de consommateur parvient à traiter chaque élément de données suffisamment rapidement, la transition en mode du noyau entraînera une (éventuellement significatif) de frais généraux. Dans ce cas, une enveloppe en mode utilisateur qui tourne pendant un moment avant d'attendre sur le sémaphore évitera une partie de cette surcharge.

Un moniteur (avec exclusion mutuelle + variable de condition) peut ou non mettre en œuvre de la filature. L'implémentation de l'article de MSDN n'a pas fait, donc dans ce cas, il n'y a pas de différence réelle dans la performance. Quoi qu'il en soit, vous allez toujours avoir à verrouiller afin de déshabiller des objets, sauf si vous utilisez une file d'attente sans verrouillage.


0 commentaires

10
votes

TLDR Je viens de courir mon propre référence et de ma configuration, il semble que verrouillage fonctionne presque deux fois plus vite que semaphoreslim (1) .

spécifications :

  • .NET CORE 2.1.5
  • Windows 10
  • 2 cœurs physiques (4 logiques) @ 2.5 GHz

    le test :

    J'ai essayé d'exécuter 2, 4 et 6 Tâche s en parallèle, chacun d'entre eux faisant 1M de opérations d'accès à une serrure, faire une opération triviale et la libérant. Le code ressemble comme suit: xxx

    résultats Pour chaque cas, verrouillage a couru presque deux fois aussi vite que semaphoreslim (1) (par exemple, 205ms vs 390ms 390ms 6 Tâches parallèles).

    Veuillez noter , je ne prétends pas qu'il est plus rapide sur un nombre infini d'autres configurations.


2 commentaires

Il faut plutôt comparer le verrouillage vs spinlock. Pour plus d'informations, recherchez "PerformanceCharacteristicsOsSyncPrimitives.pdf" ici: Microsoft. com / fr-nous / télécharger / détails.aspx? id = 12594


Le si sera optimisé, de sorte qu'il est inutile. J'utiliserais également régulièrement attendre au lieu de waitasync , comme cela a le potentiel d'interrupteurs de fil. Que nous ne voulons pas mesurer.



1
votes

Le verrouillage et le sémaphore mince sont totalement différents et je vous éviterais de les mélanger. Semaphoreslim est bon si vous utilisez Async correctement.

Si votre verrou entoure un appel Await, rappelez-vous que le fil qui ramasse fonctionne après un attente ne sera pas nécessairement le même fil qui l'appelait. Il est probable être le même threadcontext mais c'est une chose différente.

Également si votre méthode renvoie une tâche et que votre méthode contient une serrure, vous trouverez l'une des threads threadpool utilisés pour exécuter cette tâche sera bloquée jusqu'à ce que la serrure soit libérée, vous pourriez donc finir par affamer n'importe quelle tâche arbitraire quelque part sinon dans votre programme des threads, ils doivent courir.


2 commentaires

La référence de langue C # dit explicitement que "vous ne pouvez pas utiliser l'opérateur attendu dans le corps d'une déclaration de verrouillage". docs.microsoft.com/en-us/ DotNet / Csharp / Langue-Référence / ...


@Andersemil Bon point mais vous n'avez pas besoin d'utiliser une déclaration de verrouillage pour verrouiller un objet. Vous pouvez utiliser System.Trireading.Monitor ... auquel cas le mélange asynchronisé et le verrouillage s'améliorera probablement mal, à la place de SEMAPHORESLIM sera probablement mieux terminé.