2012-04-16 10 views
21

Gibt es eine Möglichkeit, mehrere Elemente gleichzeitig zu ConcurrentBag hinzuzufügen, statt einzeln? Ich sehe keine AddRange() -Methode auf ConcurrentBag, aber es gibt eine Concat(). Allerdings arbeitet das ist nicht für mich:ConcurrentBag - Mehrere Elemente hinzufügen?

ConcurrentBag<T> objectList = new ConcurrentBag<T>(); 

timeChunks.ForEach(timeChunk => 
{ 
    List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime); 
    objectList.Concat<T>(newList); 
}); 

Dieser Code wird verwendet in einem Parallel.ForEach() zu sein, aber ich änderte es zu der oben so konnte ich es beheben. Die Variable newList hat zwar Objekte, aber nach der objectList.Concat <> Zeile hat objectList immer 0 Objekte. Funktioniert Concat <> nicht so? Muss ich mit der Add() - Methode nacheinander Elemente zu ConcurrentBag hinzufügen?

Antwort

5

Ja :)

Concat ist vielleicht einer der Enumerable Erweiterungen. Es fügt nichts dem ConcurrentBag hinzu, es gibt nur ein funky Objekt zurück, das die ursprüngliche Tasche enthält und was auch immer Sie versuchten, dort hinzuzufügen.

Vorsicht, das Ergebnis von Concat ist kein ConcurrentBag mehr, so dass Sie es nicht verwenden möchten. Es ist Teil des allgemeinen LINQ-Frameworks, das es ermöglicht, unveränderliche Sequenzen zu kombinieren. Dieses Framework versucht natürlich nicht, die konkurrierenden Eigenschaften der Operanden auf das Ergebnis zu erweitern, so dass das resultierende Objekt nicht so gut für Multithread-Zugriff geeignet ist.

(Grundsätzlich gilt Concat zu ConcurrentBag weil es IEnumerable<T> Schnittstelle aussetzt.)

19

Concat ist eine Erweiterung Methode von LINQ bereitgestellt. Es ist eine unveränderliche Operation, die ein weiteres IEnumerable zurückgibt, das die Quellsammlung aufzählen kann, auf die sofort die angegebene Auflistung folgt. Es ändert in keiner Weise die Quellensammlung.

Sie müssen Ihre Artikel nacheinander zu ConcurrentBag hinzufügen.

3

Ich sah mich einem ähnlichen Problem gegenüber und versuchte, kleinere Datenblöcke parallel zu verarbeiten, weil ein großer Chunk den Web-Service verzögerte, den ich benutzte, um auf meine Daten auf der sendenden Seite zuzugreifen, aber ich wollte nicht, dass die Dinge langsamer liefen durch serielles Verarbeiten jedes Blocks. Die Verarbeitung des Datensatzes nach Datensatz war noch langsamer - da der Dienst, den ich anruft, mit Massenanfragen umgehen konnte, wäre es besser, so viele wie möglich ohne Zeitüberschreitung einzureichen.

Wie Vlad sagte, die Concatting einer gleichzeitigen Tasche zu einer Liste eines Objekttyps gibt keine gleichzeitige Tasche zurück, so concat wird nicht funktionieren! (Es dauerte eine Weile, bis mir klar wurde, dass ich das nicht konnte.)

Versuchen Sie es stattdessen - erstellen Sie eine List<T>, und erstellen Sie dann eine ConcurrentBag<List<T>>. Bei jeder parallelen Iteration wird eine neue Liste zu der konkurrierenden Tasche hinzugefügt. Wenn die parallele Schleife fertig ist, durchlaufen Sie die ConcurrentBag und concat (oder Union, wenn Sie mögliche Duplikate entfernen wollen) auf die erste List<T>, die Sie erstellt haben, um alles in eine Liste zu "glätten".

+0

Verwenden Sie am Ende SelectMany. –

17

(Ich weiß, das ist ein alter Beitrag, dachte ich würde etwas hinzufügen).

Wie andere gesagt haben: ja, Sie müssen sie einzeln hinzufügen.In meinem Fall habe ich eine kleine Erweiterung Methode die Dinge ein wenig sauberer zu machen, aber unter der Haube tut es das Gleiche:

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) 
    { 
     foreach (var element in toAdd) 
     { 
      @this.Add(element); 
     } 
    } 

Und dann:

ConcurrentBag<int> ccBag = new ConcurrentBag<int>(); 
    var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 }; 
    ccBag.AddRange(listOfThings); 

Ich sah auch bei AsParallel mit innerhalb der Erweiterungsmethode hinzuzufügen, aber nach dem Ausführen einiger Tests beim Hinzufügen einer Liste von Strings verschiedener Größen war es immer langsamer, AsParallel zu verwenden (wie hier gezeigt), im Gegensatz zur traditionellen for-Schleife.

public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd) 
    { 
     toAdd.AsParallel().ForAll(t => @this.Add(t)); 
    }