Multithreading nicht schneller als einzigen thread (simple-loop-test)
Ich experimentiere mit einigen multithreading-Konstruktionen, aber irgendwie scheint es, dass multithreading nicht schneller als ein einzelner thread. Ich verengt Sie sich auf einen sehr einfachen test mit einer verschachtelten Schleife (1000x1000), in dem das system zählt nur.
Unten habe ich gepostet der code für single-threading und Multi-Threading und wie Sie ausgeführt werden.
Das Ergebnis ist, dass die single-thread schließt die Schleife in etwa 110 ms, während die beiden threads auch über 112 ms.
Ich glaube nicht, dass das problem ist der overhead von multithreading. Wenn ich nur die Einreichung eines von beiden Runnables an den ThreadPoolExecutor, es führt in der Hälfte der Zeit der einzige thread, der Sinn macht. Aber hinzufügen, dass der zweite Thread macht es 10 mal langsamer. Beide 3.00 Ghz Kerne laufen auf 100%.
Ich denke, es kann pc-spezifisch, als jemand anderes die pc zeigte, double-speed-Ergebnisse auf dem multithreading. Aber dann, was kann ich dagegen tun? Ich habe einen Intel Pentium 4 3.00 GHz (2 CPUs) und Java jre6.
Test-code:
//Single thread:
long start = System.nanoTime(); //Start timer
final int[] i = new int[1]; //This is to keep the test fair (see below)
int i = 0;
for(int x=0; x<10000; x++)
{
for(int y=0; y<10000; y++)
{
i++; //Just counting...
}
}
int i0[0] = i;
long end = System.nanoTime(); //Stop timer
Dieser code ausgeführt wird, in etwa 110 ms.
//Two threads:
start = System.nanoTime(); //Start timer
//Two of the same kind of variables to count with as in the single thread.
final int[] i1 = new int [1];
final int[] i2 = new int [1];
//First partial task (0-5000)
Thread t1 = new Thread() {
@Override
public void run()
{
int i = 0;
for(int x=0; x<5000; x++)
for(int y=0; y<10000; y++)
i++;
i1[0] = i;
}
};
//Second partial task (5000-10000)
Thread t2 = new Thread() {
@Override
public void run()
{
int i = 0;
for(int x=5000; x<10000; x++)
for(int y=0; y<10000; y++)
i++;
int i2[0] = i;
}
};
//Start threads
t1.start();
t2.start();
//Wait for completion
try{
t1.join();
t2.join();
}catch(Exception e){
e.printStackTrace();
}
end = System.nanoTime(); //Stop timer
Dieser code ausgeführt wird, in etwa 112 ms.
Edit: ich habe die Runnables zu Threads und entledigte sich der ExecutorService (für die Einfachheit des Problems).
Edit: habe versucht einige Vorschläge
- Also, haben Sie versucht, die Vorschläge?
- Ah, Pentium4 - siehe meine aktualisierte Antwort 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie definitiv nicht wollen, zu halten polling
Thread.isAlive()
- dieser verbrennt eine Menge CPU-Zyklen für keinen guten Grund. VerwendenThread.join()
statt.Auch, es ist wahrscheinlich nicht eine gute Idee, die threads Inkrementieren den Ergebnis-arrays direkt, cache-Linien und alle. Aktualisieren der lokalen Variablen, und führen Sie einen einzelnen Speicher, wenn die Berechnungen fertig sind.
EDIT:
Total übersehen, dass man mit einem Pentium 4. Soweit ich weiß, gibt es keine multi-core-Versionen des P4 - zu geben, die illusion von multicore, es hat Hyper-Threading: zwei logische Kerne Anteil der Ausführung Einheiten einer physischen Kern. Wenn Ihr threads hängen auf der gleichen Ausführung Einheiten, wird deine Leistung die gleiche wie (oder sogar noch schlechter!) die single-Thread-Leistung. Sie müssten, zum Beispiel, floating-point-Berechnungen in einem thread und integer-calcs in einem anderen zu gewinnen performance-Verbesserungen.
Den P4-HT-Umsetzung kritisiert worden, eine Menge, in neueren Implementierungen (aktuelle core2) sollte besser sein.
Erhöhen Sie die Größe des Arrays etwas. Nein, wirklich.
Kleine Objekte zugeordnet sind nacheinander im selben thread wird tendenziell zunächst sequenziell zugeordnet. Das ist wahrscheinlich in der gleichen cache-Zeile. Wenn Sie zwei Kerne auf den gleichen cache-Zeile (und dann micro-benhcmark ist im Grunde nur tun, eine Folge von Schreibzugriffen auf die gleiche Adresse), dann werden Sie zu kämpfen haben für den Zugriff.
Es gibt eine Klasse in
java.util.concurrent
hat eine Reihe von ungenutztenlong
Felder. Ihr Zweck ist die getrennte Objekte an, die Häufig von verschiedenen threads in verschiedenen cache-lines.Ich bin überhaupt nicht überrascht über den Unterschied. Sie sind in der Java-concurrency-framework zum erstellen deines threads (obwohl ich nicht sehen, keine Garantie, dass zwei threads sind sogar seit dem ersten job könnte abgeschlossen sein, bevor die zweite beginnt.
Wahrscheinlich gibt es alle möglichen sperren und der synchronisation passiert hinter den kulissen, die Sie nicht wirklich benötigen für Ihren einfachen test. Kurz gesagt, ich tun denke, das problem ist der overhead von multithreading.
Du nichts mit mir, so Ihr loop ist wahrscheinlich nur optimierte entfernt.
Haben Sie überprüft, die Anzahl der verfügbaren Kerne auf Ihrem PC mit der Laufzeit.getRuntime().availableProcessors() ?
Ihren code einfach inkrementiert eine variable - das ist eine sehr schnelle Bedienung sowieso. Sie sind nicht zu gewinnen viel von der Verwendung mehrerer threads hier. Performance-Gewinne werden noch deutlicher, wenn thread 1 muss warten auf eine externe Antwort oder führen Sie einige komplexere Berechnungen inzwischen dein main-thread oder einem anderen thread kann weiter verarbeiten und ist nicht gehalten, die oben warten. Sie mag mehr Gewinne, wenn Sie gezählt oder höher verwendet mehrere threads (wohl eine sichere Nummer ist die Anzahl der CPU-Kerne in Ihrem Rechner haben).