134 votes

Comment retirer un objet unique et spécifique d'un ConcurrentBag<> ?

Avec le nouveau ConcurrentBag<T> dans .NET 4, comment supprimer un certain objet spécifique de celui-ci lorsque seulement TryTake() y TryPeek() sont disponibles ?

Je pense utiliser TryTake() et ensuite ajouter l'objet résultant dans la liste si je Ne le fais pas. veulent l'enlever, mais j'ai l'impression que je pourrais manquer quelque chose. Est-ce la bonne méthode ?

117voto

Mark Byers Points 318575

La réponse courte : vous ne pouvez pas le faire de manière simple.

Le ConcurrentBag conserve une file d'attente locale pour chaque thread et ne consulte les files d'attente des autres threads que lorsque sa propre file d'attente est vide. Si vous retirez un élément et le remettez en place, le prochain élément que vous retirez peut être le même élément. Il n'y a aucune garantie que le fait de retirer des éléments et de les remettre en place de façon répétée vous permettra d'itérer sur tous les éléments.

Deux alternatives pour vous :

  • Retirez tous les éléments et mémorisez-les, jusqu'à ce que vous trouviez celui que vous voulez retirer, puis remettez les autres après. Notez que si deux fils essayent de faire cela simultanément, vous aurez des problèmes.
  • Utilisez une structure de données plus adaptée, telle que ConcurrentDictionary .

15 votes

SynchronizedCollection pourrait également constituer un substitut approprié.

3 votes

@ILIABROUDNO -- vous devriez mettre cela comme réponse ! C'est TELLEMENT mieux qu'un ConcurrentDictionary maladroit lorsque vous n'avez pas besoin d'un dictionnaire.

4 votes

Pour information, SynchronizedCollection n'est pas disponible dans .NET Core. À la date de ce commentaire, les types System.Collections.Concurrent sont la voie à suivre pour les implémentations basées sur .NET Core.

18voto

Hans Passant Points 475940

Tu ne peux pas. C'est un sac, il n'est pas commandé. Quand tu le remettras, tu seras juste coincé dans une boucle sans fin.

Vous voulez un ensemble. Vous pouvez en émuler un avec ConcurrentDictionary. Ou un HashSet que vous protégez vous-même avec un verrou.

9 votes

Veuillez développer. Qu'utiliseriez-vous comme clé dans le ConcurrentDictionary sous-jacent ?

2 votes

Je suppose que la clé est le type d'objet que vous essayez de stocker, et que la valeur est une sorte de collection. Cela permettrait d'"émuler" un HashSet comme il le décrit.

14voto

Larry Points 6257

Le ConcurrentBag est idéal pour gérer une liste où vous pouvez ajouter des éléments et énumérer à partir de plusieurs fils, puis finalement la jeter comme son nom l'indique :)

Comme Mark Byers l'a dit Si vous souhaitez supprimer un élément, vous pouvez reconstruire un nouveau ConcurrentBag qui ne contient pas l'élément que vous souhaitez supprimer, mais vous devez le protéger contre les attaques de plusieurs threads en utilisant un verrou. Il s'agit d'une simple phrase :

myBag = new ConcurrentBag<Entry>(myBag.Except(new[] { removedEntry }));

Cela fonctionne, et correspond à l'esprit dans lequel le ConcurrentBag a été conçu.

5voto

Rkaufman Points 74

Mark a raison de dire que le ConcurrentDictionary fonctionne comme vous le souhaitez. Si vous souhaitez toujours utiliser un ConcurrentBag les éléments suivants, qui ne sont pas efficaces, vous permettront d'y parvenir.

var stringToMatch = "test";
var temp = new List<string>();
var x = new ConcurrentBag<string>();
for (int i = 0; i < 10; i++)
{
    x.Add(string.Format("adding{0}", i));
}
string y;
while (!x.IsEmpty)
{
    x.TryTake(out y);
    if(string.Equals(y, stringToMatch, StringComparison.CurrentCultureIgnoreCase))
    {
         break;
    }
    temp.Add(y);
}
foreach (var item in temp)
{
     x.Add(item);
}

4voto

Mikael Svenson Points 18243

Comme vous le mentionnez, TryTake() est la seule option. C'est également l'exemple sur MSDN . Reflector ne montre pas non plus d'autres méthodes internes cachées d'intérêt.

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