Code läuft 6 mal langsamer mit 2 Threads als mit 1

8

Ursprüngliches Problem:

Also habe ich Code geschrieben, um mit Threads zu experimentieren und ein paar Tests durchzuführen.

Der Code sollte einige Zahlen erstellen und dann den Mittelwert dieser Zahlen finden.

Ich denke, es ist einfach einfacher, Ihnen zu zeigen, was ich bisher habe. Ich habe mit zwei Threads erwartet, dass der Code etwa 2 mal so schnell laufen würde. Vermessung mit einer Stoppuhr Ich denke, es läuft etwa 6 mal langsamer! EDIT: Jetzt mit dem Computer und Uhr () -Funktion, um die Zeit zu sagen.

%Vor%

Ich denke nicht, dass dieser Code wirklich wunderbar ist, wenn Sie Möglichkeiten vorschlagen könnten, ihn zu verbessern, wäre ich auch dafür dankbar.

Variable registrieren:

Mehrere Leute haben vorgeschlagen, eine lokale Variable für die Funktion 'findmean' zu erstellen. Das habe ich getan:

%Vor%

Ich kann jetzt berichten: Der Code läuft fast mit der gleichen Ausführungszeit wie mit einem einzelnen Thread. Das ist eine große Verbesserung von 6x, aber sicherlich muss es einen Weg geben, es fast doppelt so schnell zu machen?

Register Variable und O2 Optimierung:

Ich habe die Optimierung auf 'O2' eingestellt - ich werde eine Tabelle mit den Ergebnissen erstellen.

Bisherige Ergebnisse:

Originalcode ohne Optimierungs- oder Registervariable: 1 Thread: 4,98 Sekunden, 2 Threads: 29,59 Sekunden

Code mit hinzugefügter Registervariable: 1 Thema: 4,76 Sekunden, 2 Themen: 4,76 Sekunden

Mit Reg-Variable und -O2-Optimierung: 1 Thread: 0.43 Sekunden, 2 Threads: 0.6 Sekunden 2 Threads ist jetzt langsamer?

Mit Dameons Vorschlag, einen großen Speicherblock zwischen die beiden Ergebnisvariablen zu setzen: 1 Thema: 0.42 Sekunden, 2 Themen: 0.64 Sekunden

Mit TAS 'Vorschlag, Iteratoren zu verwenden, um auf den Inhalt des Vektors zuzugreifen: 1 Faden: 0,38 Sekunden, 2 Fäden: 0,56 Sekunden

Wie oben bei Core i7 920 (Einzelkanalspeicher 4 GB): 1 Thema: 0,31 Sekunden, 2 Themen: 0,56 Sekunden

Wie oben bei Core i7 920 (Dual-Channel-Speicher 2x2GB): 1 Thema: 0,31 Sekunden, 2 Themen: 0,35 Sekunden

    
user3728501 27.06.2013, 16:16
quelle

4 Antworten

16
  

Warum sind 2 Threads 6x langsamer als 1 Thread?

Sie werden von einem schlechten Fall von falschem Teilen getroffen.

  

Warum sind 2 Threads nicht schneller als 1 Thread?

Sie sind durch Ihre Speicherbandbreite eingeschränkt.

Falsche Freigabe:

Das Problem hierbei ist, dass jeder Thread auf die Variable result an benachbarten Speicherorten zugreift. Es ist wahrscheinlich, dass sie auf die gleiche Cache-Line fallen, so dass jedes Mal, wenn ein Thread darauf zugreift, die Cache-Line zwischen den Kernen springt.

Jeder Thread führt diese Schleife aus:

%Vor%

Und Sie können sehen, dass auf die Variable result sehr oft zugegriffen wird (jede Iteration). Bei jeder Iteration kämpfen die Threads um dieselbe Cacheline, die beide Werte von result enthält.

Normalerweise sollte der Compiler *result in ein Register schreiben und dadurch den ständigen Zugriff auf diesen Speicherort entfernen. Da Sie jedoch nie Optimierungen aktiviert haben, ist es sehr wahrscheinlich, dass der Compiler immer noch auf den Speicherort zugreift und somit bei jeder Iteration der Schleife falsche Sharing-Strafen verursacht.

Speicherbandbreite:

Sobald Sie die falsche Freigabe beseitigt und die 6-fache Verlangsamung beseitigt haben, liegt der Grund, warum Sie keine Verbesserung erhalten, darin, dass Sie Ihre Speicherbandbreite ausgeschöpft haben.

Sicher, Ihr Prozessor kann vier Kerne haben, aber alle haben die gleiche Speicherbandbreite. Ihre spezielle Aufgabe, ein Array zu summieren, arbeitet sehr wenig (rechnerisch) für jeden Speicherzugriff. Ein einziger Thread reicht bereits aus, um die Speicherbandbreite zu maximieren. Daher wird es nicht sehr wahrscheinlich, dass Sie zu mehr Threads kommen.

Kurz gesagt, nein, Sie können ein Array nicht wesentlich schneller summieren, indem Sie mehr Threads darauf werfen.

    
Mysticial 27.06.2013, 16:21
quelle
2

Wie in anderen Antworten angegeben, sehen Sie eine falsche Freigabe für die Ergebnisvariable, aber es gibt auch einen anderen Ort, an dem dies geschieht. Die Funktion std::vector<T>::at() (sowie die std::vector<T>::operator[]() ) greifen bei jedem Elementzugriff auf die Länge des Vektors zu. Um dies zu vermeiden, sollten Sie zur Verwendung von Iteratoren wechseln. Mit std::accumulate() können Sie außerdem Optimierungen in der von Ihnen verwendeten Standardbibliotheksimplementierung nutzen.

Hier sind die relevanten Teile des Codes:

%Vor%

und

%Vor%

Dies gibt mir immer bessere Leistung für zwei Threads auf meinem 32-Bit-Netbook.

    
TAS 27.06.2013 19:07
quelle
1

Mehr Threads heißt nicht schneller! Es gibt einen Overhead beim Erstellen und Kontextwechsel von Threads, sogar bei der Hardware, in der dieser Codeverlauf die Ergebnisse beeinflusst. Für solch eine triviale Arbeit wie diese ist es wahrscheinlich besser ein einzelner Thread.

    
Oscar 27.06.2013 16:22
quelle
0

Dies liegt wahrscheinlich daran, dass die Kosten für das Starten und Warten auf zwei Threads viel mehr sind als das Berechnen des Ergebnisses in einer einzelnen Schleife. Ihre Datengröße beträgt 128 MB, was moderne Prozessoren nicht in einer einzigen Schleife verarbeiten können.

    
Kourosh 27.06.2013 16:21
quelle