2016-04-20 17 views
1

Ich habe eine Methode, die eine Textdatei liest, die einen int-Wert pro Zeile enthält, um das Lesen schneller zu machen, verwendete ich Parallel.ForEach, aber das Verhalten, was ich sehe, ist unerwartet, ich habe 800 Zeilen die Datei, aber wenn ich diese Methode ausführen, jedes Mal, wenn es verschiedene Anzahl von HashSet zurückgibt, was ich nach der Suche gelesen habe, ist Parallel.ForEach spawns mehrere Threads und es gibt das Ergebnis zurück, wenn alle Threads ihre Arbeit abgeschlossen haben, aber mein Code ausführen widerspricht, oder ich fehlt etwas Wichtiges hier?Parallel.ForEach zurückkehrendes inkonsistentes Ergebnis

Hier ist meine Methode:

private HashSet<int> GetKeyItemsProcessed() 
{ 
    HashSet<int> keyItems = new HashSet<int>(); 

    if (!File.Exists(TrackingFilePath)) 
    return keyItems; 

    // normal foreach works fine 

    //foreach(var keyItem in File.ReadAllLines(TrackingFilePath)) 
    //{ 
    // keyItems.Add(int.Parse(keyItem)); 
    //} 


    // this does not return right number of hashset rows 
    Parallel.ForEach(File.ReadAllLines(TrackingFilePath).AsParallel(), keyItem => 
    { 
     keyItems.Add(int.Parse(keyItem)); 
    }); 


    return keyItems; 

} 
+0

Ich kann wetten, das ist nicht "C". –

+0

Es war ein Fehler –

+3

Ändern eines 'HashSet' [ist nicht Thread-sicher] (https://msdn.microsoft.com/en-us/library/bb359438 (v = vs.110) .aspx # Anchor_10). Warum verwenden Sie keine Concurent-Sammlungen wie ConcurrenDictionary oder ConcurrentQueue? –

Antwort

5

HashSet.Add ist nicht Thread-sicher.

Von MSDN:

Alle öffentlichen static (Shared in Visual Basic) Member dieses Typs sind Thread-sicher. Alle Instanzmitglieder sind nicht garantiert, Thread sicher zu sein.

Die Unvorhersehbarkeit von Multithread-Timing könnte, und scheint, Probleme verursachen.

Sie können den Zugriff in ein Synchronisierungskonstrukt einbetten, das manchmal schneller als eine gleichzeitige Sammlung ist, aber in einigen Fällen möglicherweise nicht beschleunigt. Wie andere bereits erwähnt haben, ist eine andere Möglichkeit, eine Thread-sichere Sammlung wie ConcurrenDictionary oder ConcurrentQueue zu verwenden, obwohl diese zusätzlichen Speicheraufwand haben können.

Stellen Sie sicher, dass Sie alle Ergebnisse in Bezug auf das Timing benchmarken. Die rohe Leistung des eingängigen Zugriffs kann manchmal schneller sein als der Overhead des Threads. Es lohnt sich vielleicht gar nicht, diesen Code einzufädeln.

Das letzte Wort ist, dass HashSet allein, ohne Synchronisation, ist einfach nicht akzeptabel für Multithread-Operationen.

+0

Eine 'Sperre' über eine synchrone Auflistung kann schneller sein als die Verwendung einer gleichzeitigen Auflistung. Es hängt von der Höhe der Konkurrenz ab. Eigentlich sollten wir einen Schritt weiter gehen: "Parallel.ForEach" ist im OP-Szenario nicht unbedingt schneller. Einfaches sequentielles Lesen der Zeilen kann sich leicht über den parallelen Overhead hinwegsetzen. (Natürlich geht das über den Rahmen der ursprünglichen Frage hinaus, die einfach fragt, warum das Ergebnis inkonsistent ist.) –

+0

Guter Punkt. Ich werde meine Antwort aktualisieren, um das zu reflektieren. –

+0

@JeroenMostert in Disk-E/A-Parallelität wird nicht helfen, wenn die Datei zu groß ist? –