J'ai haché chaque mot deux fois pour ne le compter qu'une seule fois
La semaine dernière, j'ai profilé un analyseur de logs. Il compte les codes d'erreur dans un journal quotidien. La logique de base est une simple mise à jour de dictionnaire.
La plupart des développeurs l'écrivent ainsi :
if (counts.TryGetValue(code, out int c))
counts[code] = c + 1;
else
counts[code] = 1;
Ce code hache la clé deux fois. TryGetValue trouve l'entrée en calculant le hachage et en parcourant le bucket. Ensuite, l'indexeur effectue exactement le même travail pour mettre à jour la valeur. Vous gaspillez des cycles CPU sur la même clé et le même hachage, deux fois par jeton.
Vous pouvez éviter ce second passage. Utilisez CollectionsMarshal.GetValueRefOrAddDefault.
ref int slot = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, code, out _);
slot++;
Cette méthode trouve ou crée l'emplacement en une seule étape. Elle vous donne une référence directe au stockage. Vous n'effectuez qu'un seul hachage et un seul parcours de bucket. Ensuite, vous modifiez la valeur sur place.
J'ai testé cela avec 5 millions de jetons.
Résultats :
• TryGetValue + indexeur : 160,0 ms
• GetValueRefOrAddDefault : 95,0 ms
La version à une seule recherche est 1,7 fois plus rapide.
Point crucial : les allocations mémoire sont restées identiques. Cette astuce n'économise pas de mémoire. Elle n'économise que du CPU. Si votre code est lent à cause du garbage collection, ce changement ne servira à rien. Si votre code est lent à cause d'un comptage intensif, cela aidera.
Utilisez cette méthode lorsque votre boucle effectue de nombreuses mises à jour sur des clés existantes. Le bénéfice augmente à mesure que le ratio mises à jour/insertions augmente.
Attention : la référence pointe vers le stockage interne du dictionnaire. Elle ne reste valide que jusqu'au prochain changement structurel. Ne conservez pas la référence si vous ajoutez ou supprimez des clés. Récupérez la ref, modifiez la valeur, et passez à la suite.
Utilisez TryGetValue pour la plupart des tâches. C'est plus facile à lire. N'utilisez la version par référence que lorsque la boucle de votre dictionnaire constitue un goulot d'étranglement de performance.
Source : https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9
