Quelqu'un peut-il expliquer simplement ce qu'est la contention de thread?
Je l'ai googlé, mais je n'arrive pas à trouver une explication simple.
Quelqu'un peut-il expliquer simplement ce qu'est la contention de thread?
Je l'ai googlé, mais je n'arrive pas à trouver une explication simple.
Réponses:
Le conflit de threads est essentiellement une condition dans laquelle un thread attend un verrou / objet actuellement détenu par un autre thread. Par conséquent, ce thread en attente ne peut pas utiliser cet objet tant que l'autre thread n'a pas déverrouillé cet objet particulier.
Plusieurs réponses semblent se concentrer sur les conflits de verrouillage, mais les verrous ne sont pas les seules ressources sur lesquelles des conflits peuvent être rencontrés. Le conflit se produit simplement lorsque deux threads tentent d'accéder à la même ressource ou aux ressources associées de telle sorte qu'au moins l'un des threads en concurrence s'exécute plus lentement que si les autres threads n'étaient pas en cours d'exécution.
L'exemple le plus évident de conflit est celui d'un verrou. Si le thread A a un verrou et que le thread B veut acquérir ce même verrou, le thread B devra attendre que le thread A libère le verrou.
Maintenant, c'est spécifique à la plate-forme, mais le thread peut rencontrer des ralentissements même s'il n'a jamais à attendre que l'autre thread libère le verrou! En effet, un verrou protège certains types de données, et les données elles-mêmes seront souvent également contestées.
Par exemple, considérons un thread qui acquiert un verrou, modifie un objet, puis libère le verrou et effectue d'autres opérations. Si deux threads font cela, même s'ils ne se battent jamais pour le verrou, les threads peuvent s'exécuter beaucoup plus lentement qu'ils ne le feraient si un seul thread était en cours d'exécution.
Pourquoi? Supposons que chaque thread s'exécute sur son propre cœur sur un processeur x86 moderne et que les cœurs ne partagent pas un cache L2. Avec un seul thread, l'objet peut rester dans le cache L2 la plupart du temps. Avec les deux threads en cours d'exécution, chaque fois qu'un thread modifie l'objet, l'autre thread trouvera que les données ne sont pas dans son cache L2 car l'autre CPU a invalidé la ligne de cache. Sur un Pentium D, par exemple, cela entraînera l'exécution du code à la vitesse FSB, qui est bien inférieure à la vitesse du cache L2.
Étant donné qu'un conflit peut se produire même si le verrou n'est pas lui-même contesté, un conflit peut également se produire lorsqu'il n'y a pas de verrou. Par exemple, supposons que votre CPU prend en charge un incrément atomique d'une variable 32 bits. Si un thread continue d'incrémenter et de décrémenter une variable, la variable sera chaude dans le cache la plupart du temps. Si deux threads le font, leurs caches se disputeront la propriété de la mémoire contenant cette variable, et de nombreux accès seront plus lents car le protocole de cohérence du cache fonctionne pour sécuriser la propriété de chaque noyau de la ligne de cache.
Ironiquement, les verrous réduisent généralement les conflits. Pourquoi? Parce que sans verrou, deux threads pourraient fonctionner sur le même objet ou collection et provoquer de nombreux conflits (par exemple, il existe des files d'attente sans verrou). Les verrous auront tendance à désordonner les threads rivaux, permettant aux threads non concurrents de s'exécuter à la place. Si le thread A détient un verrou et que le thread B veut ce même verrou, l'implémentation peut exécuter le thread C à la place. Si le thread C n'a pas besoin de ce verrou, alors les conflits futurs entre les threads A et B peuvent être évités pendant un certain temps. (Bien sûr, cela suppose qu'il existe d'autres threads qui pourraient s'exécuter. Cela n'aidera pas si le seul moyen pour le système dans son ensemble de faire des progrès utiles est d'exécuter des threads qui se disputent.)
D' ici :
Un conflit se produit lorsqu'un thread attend une ressource qui n'est pas facilement disponible; cela ralentit l'exécution de votre code, mais peut s'éclaircir avec le temps.
Un blocage se produit lorsqu'un thread attend une ressource verrouillée par un second thread et que le second thread attend une ressource que le premier thread a verrouillée. Plus de deux threads peuvent être impliqués dans un blocage. Une impasse ne se résout jamais. Cela provoque souvent l'arrêt de l'ensemble de l'application ou de la partie qui rencontre le blocage.
Je pense que le PO devrait clarifier le contexte de la question - je peux penser à 2 réponses (même si je suis sûr qu'il y a des ajouts à cette liste):
si vous faites référence au «concept» général de conflit de threads et comment il peut se présenter dans une application, je m'en remets à la réponse détaillée de @ DavidSchwartz ci-dessus.
Il existe également le compteur de performances «.NET CLR Locks and Threads: Total # of Contentions». Comme extrait de la description PerfMon de ce compteur, il est défini comme suit:
Ce compteur affiche le nombre total de fois que les threads du CLR ont tenté d'acquérir un verrou géré sans succès. Les serrures gérées peuvent être acquises de plusieurs manières; par l'instruction «lock» en C # ou en appelant System.Monitor.Enter ou en utilisant l'attribut personnalisé MethodImplOptions.Synchronized.
... et je suis sûr que d'autres pour d'autres OS et frameworks d'application.
Un autre mot pourrait être la concurrence. C'est simplement l'idée que deux threads ou plus essaient d'utiliser la même ressource.
Pour moi, la contention est une compétition entre 2 ou plusieurs threads sur une ressource partagée. La ressource peut être un verrou, un compteur, etc. La compétition signifie «qui l'obtient en premier». Plus il y a de fils, plus il y a de conflit. Plus l'accès à une ressource est fréquent, plus il y a de conflit.
Imaginez le scénario suivant. Vous vous préparez pour l'examen final de demain et vous avez un peu faim. Alors, vous donnez dix dollars à votre jeune frère et lui demandez de vous acheter une pizza. Dans ce cas, vous êtes le thread principal et votre frère est un thread enfant. Une fois votre commande passée, vous et votre frère faites leur travail simultanément (c.-à-d. Étudier et acheter une pizza). Maintenant, nous avons deux cas à considérer. Tout d'abord, votre frère ramène votre pizza et termine pendant que vous étudiez. Dans ce cas, vous pouvez arrêter d'étudier et profiter de la pizza. Deuxièmement, vous terminez votre étude tôt et vous dormez (c'est-à-dire que le travail qui vous est assigné pour aujourd'hui - étudier pour l'examen final de demain - est terminé) avant que la pizza ne soit disponible. Bien sûr, vous ne pouvez pas dormir; sinon, vous n'aurez pas la chance de manger la pizza.
Comme dans l'exemple, les deux cas donnent un sens à la rivalité.
Un conflit de verrouillage a lieu lorsqu'un thread tente d'acquérir le verrou d'un objet qui est déjà acquis par un autre thread *. Tant que l'objet n'est pas libéré, le thread est bloqué (en d'autres termes, il est en attente). Dans certains cas, cela peut conduire à une soi-disant exécution en série qui affecte négativement l'application.
à partir de la documentation dotTrace