95 votes

Dictionnaire simultané Utilisation correcte

Ai-je raison de penser qu'il s'agit là de l'utilisation correcte d'un dictionnaire concurrent ?

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>();

//Main thread at program startup

for(int i = 0; i < 4; i++)
{
  myDic.Add(i, 0);
}

//Separate threads use this to update a value

myDic[InputID] = newLongValue;

Je n'ai pas de verrous, etc. et je ne fais que mettre à jour la valeur dans le dictionnaire, même si plusieurs threads peuvent essayer de faire la même chose.

2 votes

Cela dépend - est-ce que newLongValue dépendent de la valeur précédente de myDic[InputID] ?

3 votes

Vous devez éviter d'accéder directement par la clé myDic[InputID] pour une condition de course. Vous devez essayer GetOrAdd

3 votes

@OlivierAlbertini, je ne pense pas que myDic[InputID] ne pose aucun problème lorsqu'il est utilisé comme une valeur l. GetOrAdd n'est pas un remplacement correct puisqu'il ajoute seulement si la valeur n'existe pas. Nous pouvons utiliser à la place AddOrUpdate pour ajouter/mettre à jour la même valeur dans le dictionnaire.

86voto

Oded Points 271275

Cela dépend de ce que vous entendez par "thread-safe".

De MSDN - Comment faire : Ajouter et supprimer des éléments d'un dictionnaire simultané (ConcurrentDictionary) :

ConcurrentDictionary<TKey, TValue> est conçu pour les scénarios multithreads. Il n'est pas nécessaire d'utiliser des verrous dans votre code pour ajouter ou retirer des éléments de la collection. Cependant, il est toujours possible pour un thread de récupérer une valeur et pour un autre thread de mettre immédiatement à jour la collection en donnant une nouvelle valeur à la même clé.

Ainsi, il est possible d'obtenir une incohérence voir de la valeur d'un élément du dictionnaire.

4voto

Erdem Points 38

La meilleure façon de le savoir est de consulter la documentation MSDN.

Pour ConcurrentDictionary, la page est http://msdn.microsoft.com/en-us/library/dd287191.aspx

Dans la section sur la sécurité des threads, il est indiqué que "Tous les membres publics et protégés de ConcurrentDictionary(Of TKey, TValue) sont sûrs pour les threads et peuvent être utilisés simultanément à partir de plusieurs threads".

Donc, du point de vue de la concurrence, tout va bien.

2voto

Jan Points 10374

Oui, vous avez raison.

Cela et la possibilité d'énumérer le dictionnaire sur un thread tout en le modifiant sur un autre thread sont les seuls moyens d'existence de cette classe.

10 votes

Ce que je voudrais ajouter, c'est que aquí est une information utile sur comment et quand utiliser ConcurrentDictionary .

1voto

Onur Points 754

Cela dépend, dans mon cas je préfère utiliser cette méthode.

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>);

Voir Bibliothèque MSDN pour les détails d'utilisation de la méthode.

Exemple d'utilisation :

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });

5 votes

Pour info : "Lorsque vous fournissez une méthode de type "value factory" (aux méthodes GetOrAdd et AddOrUpdate), elle peut effectivement s'exécuter et voir son résultat rejeté par la suite (parce qu'un autre thread a gagné la course)." Plus d'informations ici : arbel.net/2013/02/03/…

2 votes

Oui, vous avez raison, car il est noté dans la section Remarques "Si vous appelez AddOrUpdate simultanément sur différents threads, addValueFactory peut être appelé plusieurs fois, mais sa paire clé/valeur peut ne pas être ajoutée au dictionnaire à chaque appel." Vous devez donc vous assurer que vous ne générez pas plusieurs objets persistants.

0 votes

Et si vous devez mettre à jour le contenu, sans changer entièrement l'objet stocké, par exemple pour modifier une propriété d'un objet précédemment ajouté, cette méthode est utile, sinon vous devez utiliser des verrous ou d'autres méthodes de synchronisation.

1voto

Antonio Leonardo Points 191

Remarque : cela ne justifie pas l'utilisation d'un ConcurrentDicitonary avec une boucle linéaire, ce qui le rend sous-utilisé. La meilleure alternative est de suivre les recommandations de la documentation Microsoft, comme mentionné par Oded en utilisant le parallélisme, selon l'exemple ci-dessous :

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X