Je travaille selon le principe du partage de la programmation simultanée. Essentiellement, tous mes threads de travail ont des copies immuables en lecture seule du même état qui n'est jamais partagé entre eux ( même par référence ). D'une manière générale, cela a très bien fonctionné.
Maintenant, quelqu'un a introduit un cache singleton sans verrouillage ( par exemple un dictionnaire statique ) auquel tous les threads accèdent simultanément. Étant donné que le dictionnaire n'est jamais modifié après le démarrage, il n'y a pas de verrous. Il n'y a eu aucun problème de sécurité des threads, mais il y a maintenant une dégradation des performances.
La question est ... puisqu'il n'y a pas de verrous pourquoi l'introduction de ce singleton crée-t-elle un succès de performance? Que se passe-t-il exactement sous les couvertures qui pourrait expliquer cela?
Pour confirmer, l'accès à ce nouveau singleton est le seul changement et je peux le recréer de manière fiable simplement en commentant l'appel au cache.
la source
Réponses:
Il se pourrait que l'état immuable partage une ligne de cache avec quelque chose de mutable. Dans ce cas, une modification de l'état mutable proche pourrait avoir pour effet de forcer une resynchronisation de cette ligne de cache sur les cœurs, ce qui pourrait ralentir les performances.
la source
false sharing
scénario que vous décrivez. Pour isoler ce dont j'ai besoin pour profiler le cache L2. Malheureusement, ce sont des types de référence, donc l'ajout d'espace tampon ne sera pas une option si c'est ce qui se passe réellement.Je m'assurerais que les méthodes
Equals()
etGetHashCode()
des objets que vous utilisez comme clés du dictionnaire n'ont pas d'effets secondaires inattendus non adaptés aux threads. Le profilage serait très utile ici.Si par hasard vos clés sont des chaînes, alors peut-être que vous l'avez: la rumeur veut que les chaînes se comportent comme des objets immuables, mais pour certaines optimisations, elles sont implémentées en interne de manière modifiable, avec tout ce que cela implique en matière de multithreading .
J'essaierais de passer le dictionnaire aux threads qui l'utilisent comme référence régulière au lieu d'un singleton pour voir si le problème réside dans le partage ou la singletonness du dictionnaire. (Éliminer les causes possibles.)
J'essaierais également avec un
ConcurrentDictionary
au lieu d'un régulierDictionary
juste au cas où son utilisation donnerait des résultats surprenants. Il y a beaucoup de choses à spéculer sur le problème à résoudre si un résultatConcurrentDictionary
s'avère bien meilleur ou bien pire que votre habituéDictionary
.Si rien de ce qui précède ne pointe vers le problème, je suppose que les performances dégradées sont causées par une sorte de conflit étrange entre le thread de collecte des ordures et le reste de vos threads, car le garbage collector essaie de déterminer si les objets de votre dictionnaire doivent être supprimés ou non, pendant qu'ils sont accessibles par vos threads.
la source