2013-07-25 6 views
8

Ich habe vor kurzem PLINQ verwendet, um einige Daten zu verarbeiten.Warum endet mein Parallel.ForAll-Aufruf mit einem einzelnen Thread?

Grundsätzlich habe ich etwa 4000 Zeitreihen (also im Grunde Instanzen von Dictionary<DataTime,T>) die ich in einer Liste timeSeries geführt habe.

meiner Operation ausführen zu können, ich tue einfach:

timeSeries.AsParallel().ForAll(x=>myOperation(x)) 

Wenn ich einen Blick auf das, was mit meinen verschiedenen Kernen geschieht, merke ich, dass zuerst sehen, alle meine CPUs benutzt werden und ich auf der Konsole (wo ich einige Protokolle ausgab), dass mehrere Zeitreihen zur gleichen Zeit verarbeitet werden.

Der Prozess ist jedoch langwierig und nach ungefähr 45 Minuten zeigt die Protokollierung deutlich an, dass nur ein Thread arbeitet. Warum das?

Ich habe versucht, einige Gedanken zu machen, und mir wurde klar, dass timeSeries Instanzen enthält, die aus Sicht der myOperation am Anfang und am Ende der Liste zu verarbeiten sind. Also, ich fragte mich, ob der Algorithmus, den PLINQ benutzte, darin bestand, die 4000 Instanzen auf etwa 4 Kernen aufzuteilen und jedem von ihnen 1000 zu geben. Wenn der Kern mit der Zuweisung der Arbeit fertig ist, geht er wieder in den Leerlauf. Dies würde bedeuten, dass einer der Kernbereiche mit einer viel größeren Arbeitslast konfrontiert wird.

Ist meine Theorie korrekt oder gibt es eine andere mögliche Erklärung?

Soll ich meine Liste mischen, bevor ich sie leite, oder gibt es Parallelparameter, die ich verwenden kann, um das Problem zu beheben?

Antwort

5

Ihre Theorie ist wahrscheinlich richtig, obwohl es etwas gibt, das als "Arbeitssteurung" bezeichnet wird und dem entgegenwirken sollte. Ich bin mir nicht sicher, warum das hier nicht funktioniert. Gibt es viele (> = Dutzende) große Jobs an den äußeren Enden oder nur wenige?

Neben dem Mischen Ihrer Daten können Sie the overload für AsParallel() verwenden, die eine custom Partioner akzeptiert. Das würde Ihnen erlauben, die Arbeit besser auszugleichen.

Randnotiz: Für diese Situation würde ich Parallel.ForEach(), mehr Optionen und sauberere Syntax bevorzugen.

+1

Soweit ich weiß, arbeitet Arbeit Diebstahl auf Aufgaben, nicht auf Iterationen in PLINQ. Wenn ein Task eine Reihe von Elementen aus der Sammlung zur Verarbeitung erhält, können andere Tasks diese nicht stehlen. – svick

+1

Auch hier ist möglicherweise kein benutzerdefinierter Partitionierer erforderlich (die vom Framework bereitgestellten) (http://msdn.microsoft.com/en-us/library/system.collections.concurrent.partitioner.create.aspx)) könnte genug sein. – svick

+0

@svick - Sie haben wahrscheinlich Recht, aber würde das auf eine For-Schleife zeigen, die eine Menge Aufgaben erzeugt? Scheint unhandlich. –

Verwandte Themen