2009-11-28 12 views
7

Angenommen, ich habe eine E/A-gebundene Aufgabe. Ich verwende WithDegreeOfParallelism = 10 und WithExecution = ForceParallelism-Modus, aber die Abfrage verwendet immer noch nur zwei Threads. Warum?Warum verwendet PLINQ nur zwei Threads?

Ich verstehe PLINQ wird in der Regel einen Grad der Parallelität gleich meiner Kernzahl wählen, aber warum ignoriert es meine spezifische Anfrage für höhere Parallelität?

static void Main(string[] args) 
{ 
    TestParallel(0.UpTo(8)); 
} 

private static void TestParallel(IEnumerable<int> input) 
{ 
    var timer = new Stopwatch(); 
    timer.Start(); 
    var size = input.Count(); 

    if (input.AsParallel(). 
     WithDegreeOfParallelism(10). 
     WithExecutionMode(ParallelExecutionMode.ForceParallelism). 
     Where(IsOdd).Count() != size/2) 
     throw new Exception("Failed to count the odds"); 

    timer.Stop(); 
    Console.WriteLine("Tested " + size + " numbers in " + timer.Elapsed.TotalSeconds + " seconds"); 
} 

private static bool IsOdd(int n) 
{ 
    Thread.Sleep(1000); 
    return n%2 == 1; 
} 
+2

Wie viele Prozessoren/Kerne haben Sie? – LukeH

+2

Zwei. Aber ich habe speziell den Grad der Parallelität als 10 angegeben. – ripper234

+0

Wenn Sie eine E/A-gebundene Aufgabe haben und sie parallel auf mehreren Threads ausführen, verbessert sich die Geschwindigkeit dann war es wahrscheinlich nicht wirklich I/O-gebunden an erster Stelle, es wurde nur schlecht geschrieben (z. B. sync liest statt async). –

Antwort

8

PLINQ versucht, die optimale Anzahl von Threads zu finden auszuführen, was Sie es so schnell wie möglich tun wollen, wenn Sie nur zwei Kerne auf Ihrer CPU haben, ist diese Zahl wahrscheinlich 2. Wenn Sie eine hatte Quad-Core, würden Sie eher 4 Threads erscheinen sehen, aber Erstellen von 4 Threads auf einem Dual-Core-Rechner würde nicht wirklich die Leistung verbessern, da nur 2 Threads zur gleichen Zeit aktiv sein könnten.

Auch bei IO-basierten Operationen ist es wahrscheinlich, dass zusätzliche Threads bei der ersten durchgeführten IO-Operation einfach blockiert werden.

+4

Beantwortet meine Frage nicht wirklich - warum wählt sie zwei Threads, obwohl ich explizit einen Parallelitätsgrad = 10 anfordere? (Aktualisierte Frage) – ripper234

+3

@ ripper234: Aus der MSDN-Dokumentation: "Grad der Parallelität ist die ** maximale ** Anzahl der gleichzeitig ausgeführten Aufgaben, die zur Verarbeitung der Abfrage verwendet werden". 'WithDegreeOfParallelism' ist nur ein Hinweis darauf, dass PLINQ * nicht mehr * als * n * Threads verwenden soll. http://msdn.microsoft.com/en-us/library/dd383719%28VS.100%29.aspx – LukeH

+3

Also ... gibt es keine Möglichkeit, PLINQ effektiv für IO-gebundene Aufgaben zu verwenden? – ripper234

4

10 maximal ist

den Grad der Parallelität Sets in einer Abfrage zu verwenden. Grad der Parallelität ist die maximale Anzahl gleichzeitig Ausführung von Aufgaben, die verwendet werden, um die Abfrage zu verarbeiten.

Von hier aus:

MSDN

+0

Standardmäßig verwendet PLINQ alle Prozessoren auf dem Host-Computer bis zu einem Maximum von ** 64 **. Sie können PLINQ anweisen, nicht mehr als eine bestimmte Anzahl von Prozessoren zu verwenden, indem Sie die WithDegreeOfParallelism (Of TSource) -Methode verwenden. http://msdn.microsoft.com/en-us/library/dd383719.aspx –

2

Es scheint PLINQ die Anzahl der Threads abstimmt. Wenn ich den obigen Code in eine While-Schleife (true-Schleife) einfügte, dauerte die erste zwei Iteration zwei Sekunden, aber die dritte und die obere dauerte nur eine Sekunde. PLINQ versteht, dass die Kerne leer sind und die Anzahl der Threads erhöht wird. Beeindruckend!

+1

Beachten Sie, dass Sie dazu WithDegreeOfParallelism angeben müssen, andernfalls würde PLINQ sich auf die Anzahl der Kerne auf Ihrem Computer beschränken. – ripper234

0

Ich würde Rory zustimmen, außer IO. Habe nicht mit Disk-IO getestet, aber Netzwerk-IO kann definitiv mit mehr Threads effektiver sein, als es Kerne auf der CPU gibt.

Einfacher Test (es wäre richtig Test mit jedem Thread zählt mehrmals ausgeführt werden, wie die Netzwerkgeschwindigkeit nicht konstant ist, aber immer noch) zu beweisen, dass:

[Test] 
    public void TestDownloadThreadsImpactToSpeed() 
    { 
     var sampleImages = Enumerable.Range(0, 100) 
      .Select(x => "url to some quite large file from good server which does not have anti DSS stuff.") 
      .ToArray();    

     for (int i = 0; i < 8; i++) 
     { 
      var start = DateTime.Now; 
      var threadCount = (int)Math.Pow(2, i); 
      Parallel.For(0, sampleImages.Length - 1, new ParallelOptions {MaxDegreeOfParallelism = threadCount}, 
         index => 
          { 
           using (var webClient = new WebClient()) 
           { 
            webClient.DownloadFile(sampleImages[index], 
                  string.Format(@"c:\test\{0}", index)); 
           } 
          }); 

      Console.WriteLine("Number of threads: {0}, Seconds: {1}", threadCount, (DateTime.Now - start).TotalSeconds); 
     } 
    } 

Ergebnis mit 500x500px Bild von CDN Verwendung von 8-Core-Maschine mit SSD war:

Anzahl der Fäden: 1, Sekunden: 25,3904522
Anzahl der Fäden: 2, Sekunden: 10,8986233
Anzahl der Fäden: 4, Sekunden: 9,9325681
Anzahl der Fäden: 8, Sekunden: 3,7352137
Anzahl der Fäden: 16 Sekunden: 3,3071892
Anzahl der Fäden: 32, Sekunden: 3,1421797
Anzahl der Fäden: 64, Sekunden: 3,1161782
Anzahl der Fäden: 128 Sekunden: 3,7272132

Letztes Ergebnis so lange ich zunächst denken hat, weil wir nur 100 Bilder herunterladen müssen :)

Unterschiede Zeit 8-64 Threads ist nicht so groß, aber das ist auf 8-Kern-Maschine.Wenn es 2-Kern-Maschine (billiges Endbenutzer-Notebook) wäre, würde ich denke, zwingen, 8 Threads zu verwenden, hätte mehr Auswirkungen, als auf 8-Core-Maschine gezwungen, 64 Threads zu verwenden.

+0

Haben Sie diese Zahlen über 10.000 Iterationen gemittelt? – ChrisF

+0

Ich habe erwähnt, dass es richtiger wäre, den Test mit jeder Threadanzahl mehrere Male auszuführen. Wie auch immer, Punkt ist es, mehr Threads für Maschinen, die eine niedrige CPU-Anzahl haben, zu erzwingen, falls Sie Netzwerk IO machen. – Giedrius

+0

Offenbar werden die parallelen Optionen für> = 8 ignoriert. Fügen Sie eine Debugging-Ausgabe innerhalb von parallel body hinzu und ich glaube, Sie werden sehen, dass nur maximal 8 gleichzeitig ausgeführt werden und es gedrosselt wird. – crokusek

Verwandte Themen