Parallel.Für jedes wiederholte Iterieren von Elementen in der Sammlung

8

Ich habe eine Parallel.ForEach innerhalb einer Aufgabe ausgeführt. Es iteriert über eine Sammlung von E-Mail-Adressen und sendet eine MailMessage an die SMTP-Warteschlange, sobald es gesendet wird, aktualisiert es eine Tabelle in der Datenbank mit einem Ergebnis.

Ich kann in der DB sehen, dass es die MailMessage mehrmals, manchmal bis zu sechs Mal, in die Warteschlange sendet. Hier ist mein vereinfachter Code, kann jemand einen besseren Ansatz empfehlen?

Beim Klicken auf die Schaltfläche erzeuge ich eine neue Aufgabe ...

%Vor%

Dies erstellt eine Aufgabe, die grundsätzlich einen ConcurrentBag von Abonnenten (benutzerdefinierte Klasse) erhält, über die Sammlung iteriert und eine Nachricht sendet ...

%Vor%

Ich bin der Ansicht, dass ConcurrentBags Thread-sicher sind, also bin ich mir nicht sicher, warum es einige in der Sammlung mehrmals durchlaufen würde. Von tausend würde es mindestens 2 Nachrichten für 10% der Sammlung in die Warteschlange stellen.

Danke,

Greg.

    
gfyans 15.08.2011, 20:15
quelle

1 Antwort

6
  

Ich bin der Ansicht, dass ConcurrentBags threadsicher sind, weshalb ich nicht sicher bin, warum es einige in der Sammlung mehrmals durchlaufen würde.

Ihre Annahme ist hier richtig. Tatsächlich erstellt ConcurrentBag<T> s GetEnumerator<T> method (zum Aufzählen der Sammlung) tatsächlich eine vollständige Kopie der internen Sammlung an diesem Punkt, sodass Sie über eine Kopie der Sammlung iterieren.

Wenn die Warteschlange für einen einzelnen Abonnenten mehrfach aufgerufen wird, bedeutet dies, dass Sie diesen Abonnenten mehrmals zu ConcurrentBag<T> hinzugefügt haben oder ein anderes Problem besteht ...

Auf einer separaten Notiz ist die Verwendung einer Aufgabe hier wirklich nicht notwendig. Es fügt nur Overhead hinzu (erzeugt in diesem Fall einen dedizierten Thread, blockt ihn sofort und wartet darauf). Es wäre viel besser, dies einfach neu zu schreiben, um Ihre Methode zu nennen, und zwar so:

%Vor%

Das Erstellen einer Aufgabe, die sofort darauf wartet ( Task.WaitAny ), ist überhaupt nicht hilfreich. Anstatt% ce_de% zu verwenden, können Sie auch Task.WaitAny(...) aufrufen, wenn Sie die Aufgabe für einen anderen Zweck verwenden möchten, da diese blockiert, bis die Aufgabe abgeschlossen ist.

    
Reed Copsey 15.08.2011, 20:30
quelle

Tags und Links