2013-05-15 13 views
12

Mein Mac ist mit 16 Kernen bestückt.Verschlechterungsleistung bei steigender Anzahl der Kerne

System.out.println(Runtime.getRuntime().availableProcessors()); //16 

Ich führe den Code unten, um die Wirksamkeit der Verwendung meiner Kerne zu sehen. Der Faden ‚CountFileLineThread‘ zählt einfach die Anzahl der Zeilen in einer Datei (Es gibt 133 Dateien in einem Ordner)

ich Notizen auf dieser Linie unter:

ExecutorService es = Executors.newFixedThreadPool(NUM_CORES); 

Wo NUM_CORES zwischen 1 bis 16 ist .

Sie werden aus dem Ergebnis unten feststellen, dass oberhalb von 5 Kernen die Leistung beginnt sich zu verschlechtern. Ich würde nicht erwarten, ein 'Produkt der abnehmenden Rendite' für 6 Kerne und höher (übrigens, für 7 Kerne dauert es über 22 Minuten, hallo?!?!) Meine Frage ist warum?

enter image description here

public class TestCores 
{ 
    public static void main(String args[]) throws Exception 
    { 
    long start = System.currentTimeMillis(); 
    System.out.println("START"); 

    int NUM_CORES = 1; 

    List<File> files = Util.getFiles("/Users/adhg/Desktop/DEST/"); 
    System.out.println("total files: "+files.size()); 
    ExecutorService es = Executors.newFixedThreadPool(NUM_CORES); 
    List<Future<Integer>> futures = new ArrayList<Future<Integer>>(); 
    for (File file : files) 
    { 
     Future<Integer> future = es.submit(new CountFileLineThread(file)); 
     futures.add(future); 
    } 

    Integer total = 0; 

    for (Future<Integer> future : futures) 
    { 
     Integer result = future.get(); 
     total+=result; 
     System.out.println("result :"+result); 

    } 

    System.out.println("----->"+total); 

    long end = System.currentTimeMillis(); 
    System.out.println("END. "+(end-start)/1000.0); 
} 
} 
+13

Weil Ihr Test Datei-I/O macht, haben Sie wahrscheinlich einen Punkt mit diesem 6. Thread erreicht, wo Sie jetzt zu viel I/O machen und somit alles verlangsamen. – cmbaxter

+2

Ich denke, das ist ein E/A-gebundener Job und kein CPU-gebundener Job. Das Hinzufügen weiterer Threads führt nur dazu, dass die Festplatte unregelmäßige Muster auf der Festplatte erhält und zwischen verschiedenen Dateien navigiert (im Gegensatz zur aufeinanderfolgenden Position für eine einzelne Datei, die auf einer regelmäßig defragmentierten Festplatte in einem modernen Betriebssystem erwartet wird). – nhahtdh

+1

Bei dieser Art von Test ist nur die Anzahl der Kerne nicht relevant, wenn der Code nur im Arbeitsspeicher ausgeführt wird. Sobald ein I/O hinzugefügt wurde, während ein Thread eine Datei gelesen hat, müssen alle anderen warten. –

Antwort

19

Ich habe diese als Kommentar, aber ich werde auch sie dort als Antwort werfen. Da Ihr Test File I/O durchführt, haben Sie wahrscheinlich einen Punkt mit dem 6. Thread erreicht, wo Sie jetzt zu viel I/O machen und somit alles verlangsamen. Wenn Sie wirklich den Vorteil der 16 Kerne sehen möchten, die Sie haben, sollten Sie Ihren Dateilese-Thread neu schreiben, um nicht blockierende E/A zu verwenden.

+0

danke, Sinn machen; Ich habe etwas Neues gelernt. – adhg

5

Meine Vermutung ist, dass Sie die Festplatten-E/A so stark belastet haben, dass Sie alles verlangsamt haben! Siehe die E/A-Leistung in "Activity Monitor" (wenn Sie unter OSX sind). Unter Linux verwenden Sie den Befehl vmstat, um eine Vorstellung davon zu bekommen, was vor sich geht. [Wenn Sie viel Swapping oder hohe Rate von Lese-/s und schreibt/s sehen dann los gehts]


Ein paar Dinge, die ich bemerkt:

CountFileLineThread ist im Code nicht. Bitte stellen Sie es so, dass wir genau sehen können, was vor sich geht.

Als nächstes

for (Future<Integer> future : futures) 
{ 
    Integer result = future.get(); 
    total+=result; 
    System.out.println("result :"+result); 

} 

klar sein, dass Sie auf auf dem Ergebnis der ersten Task (future.get()) blockiert sind. Die anderen Ergebnisse sind möglicherweise bereits verfügbar, aber Sie können sie erst sehen, wenn die ersten Ergebnisse vorliegen. Verwenden Sie stattdessen CompletionService, um die Ergebnisse in der Reihenfolge zu erhalten, in der sie für eine bessere Messung abgeschlossen sind. Es spielt jedoch keine Rolle, da alle Threads vor dem Ende des Timers ausgeführt werden sollen.

Ein weiterer Punkt: Blockieren von E/A ist der Schlüssel. Es spielt keine Rolle, wie viele Cores Sie haben, wenn die Tasks auf E/A, Netzwerk usw. blockiert sind. Moderne Prozessoren haben Hyper Threading und können einen Thread ausführen, der darauf wartet ausgeführt zu werden, wenn aktuell Thread-Blöcke ausgeführt werden .

Also zum Beispiel, wenn ich 16 Kerne habe und ich spawn 16 Threads fragen sie 1 GB-Dateien zu lesen, werde ich keine Leistungsverbesserungen nur durch mehr Kerne haben. Der Engpass ist die Festplatte und der Speicher.

1

Hinzufügen von Prozessoren verursacht alle möglichen Probleme, aber meistens haben sie mit der Synchronisation zwischen Prozessoren zu tun. Das Sperren auf der Aufgabenebene innerhalb des Dateisystems usw. kann zu einem Problem werden, aber ein noch größeres Problem ist die Synchronisierung zwischen Kernen, die nur auftreten muss, um die Kohärenz des Caches aufrechtzuerhalten, geänderte Seiten zu verfolgen usw.Ich weiß nicht, wie viele Kerne pro Chip Sie haben (gab auf, das Zeug vor etwa 10 Jahren zu verfolgen), aber im Allgemeinen, wenn Sie anfangen, die Leistung außerhalb des Chips zu synchronisieren, geht die Röhren runter.

Ich füge hinzu, dass die JVM kann hier einen großen Unterschied machen. Ein sorgfältiger JVM-Entwurf ist erforderlich, um die Anzahl der gemeinsamen (und häufig aktualisierten) Cache-Zeilen zu minimieren, und unglaubliche Anstrengungen sind erforderlich, damit GC in einer Multicore-Umgebung effizient arbeiten kann.

Verwandte Themen