Frage

Ich profiliere ein Multithread-Programm, das mit einer unterschiedlichen Anzahl zulässiger Threads ausgeführt wird. Hier sind die Leistungsergebnisse von drei Läufen derselben Eingabearbeit.

1 thread:
  Total thread time: 60 minutes.
  Total wall clock time: 60 minutes.

10 threads:
  Total thread time: 80 minutes. (Worked 33% longer)
  Total wall clock time: 18 minutes.  3.3 times speed up

20 threads
  Total thread time: 120 minutes. (Worked 100% longer)
  Total wall clock time: 12 minutes.  5 times speed up

Da die gleiche Arbeit mehr Thread-Zeit benötigt, müssen die Threads meiner Meinung nach um Ressourcen kämpfen.

Ich habe bereits die vier Säulen (CPU, Speicher, DiskIO, Netzwerk) sowohl auf dem App-Computer als auch auf dem Datenbankserver untersucht. Speicher war die ursprünglich umstrittene Ressource, aber das ist jetzt behoben (mehr als 1G jederzeit frei). Die CPU bewegt sich beim 20-Thread-Test zwischen 30% und 70%, also viel. diskIO ist auf dem App-Computer praktisch nicht vorhanden und auf dem Datenbankserver minimal. Das Netzwerk ist wirklich großartig.

Ich habe auch ein Code-Profil mit Redgate erstellt und sehe keine Methoden, die auf Sperren warten. Es hilft, dass die Threads keine Instanzen gemeinsam nutzen. Jetzt überprüfe ich nuanciertere Elemente wie das Herstellen / Poolen von Datenbankverbindungen (wenn 20 Threads versuchen, eine Verbindung zu derselben Datenbank herzustellen, müssen sie aufeinander warten?).

Ich versuche, den Ressourcenkonflikt zu identifizieren und zu beheben, sodass der 20-Thread-Lauf folgendermaßen aussehen würde:

20 threads
  Total thread time: 60 minutes. (Worked 0% longer)
  Total wall clock time: 6 minutes.  10 times speed up

Was sind die wahrscheinlichsten Quellen (außer den großen 4), nach denen ich suchen sollte, um diese Behauptung zu finden?


Der Code, den jeder Thread ausführt, ist ungefähr:

Run ~50 compiled LinqToSql queries
Run ILOG Rules
Call WCF Service which runs ~50 compiled LinqToSql queries, returns some data
Run more ILOG Rules
Call another WCF service which uses devexpress to render a pdf, returns as binary data
Store pdf to network
Use LinqToSql to update/insert. DTC is involved: multiple databases, one server.

Die WCF-Dienste werden auf demselben Computer ausgeführt, sind zustandslos und können mehrere gleichzeitige Anforderungen verarbeiten.


Maschine hat 8 CPUs.

War es hilfreich?

Lösung

Was Sie beschreiben, ist, dass Sie eine Skalierbarkeit von 100% wünschen, die eine 1: 1-Beziehung zwischen der Zunahme der Threads und der Abnahme der Wallcklock-Zeit darstellt. Dies ist normalerweise ein Ziel, aber schwer zu erreichen.

Zum Beispiel schreiben Sie, dass es keine Speicherkonflikte gibt, weil 1 GB frei ist ... dies ist meiner Meinung nach eine falsche Annahme ... Speicherkonflikte bedeuten auch, dass es passieren kann, dass zwei Threads versuchen, Speicher zuzuweisen Warten Sie auf den anderen ... Ein weiterer Punkt, den Sie beachten sollten, sind die Unterbrechungen durch GC, die alle Threads vorübergehend einfrieren ... Der GC kann über die Konfiguration (gcServer) ein wenig angepasst werden - siehe http://blogs.msdn.com/b/clyon/archive/2004/09/08 /226981.aspx

Ein weiterer Punkt ist der WCF-Dienst namens ... Wenn er nicht skaliert werden kann - zum Beispiel das PDF-Rendering -, ist dies auch eine Form von Streit, zum Beispiel ...

Die Liste möglicher Konflikte ist "endlos" ... und kaum immer in den offensichtlichen Bereichen, die Sie erwähnt haben ...

BEARBEITEN - gemäß Kommentar:

Einige zu überprüfende Punkte:

Andere Tipps

Anstatt die gesamte Thread-Zeit zu messen, messen Sie die Zeit für jede der Operationen, die Sie ausführen, um E / A-Vorgänge auszuführen (Datenbank, Festplatte, Netz usw.).

Ich vermute, Sie werden feststellen, dass diese Vorgänge länger dauern, wenn Sie mehr Threads haben. Dies liegt daran, dass sich der Konflikt am anderen Ende dieser E / A befindet.Beispielsweise serialisiert Ihre Datenbank möglicherweise Anforderungen für die Datenkonsistenz.

Ja, es gibt Ressourcenkonflikte. Alle Threads müssen Daten auf denselben Speicherbus lesen / schreiben, der beispielsweise auf dieselben RAM-Module gerichtet ist. Es spielt keine Rolle, wie viel RAM frei ist, es ist wichtig, dass die Lese- / Schreibvorgänge von demselben Speichercontroller auf denselben RAM-Modulen ausgeführt werden und dass die Daten über denselben Bus übertragen werden.

Wenn es irgendwo eine Synchronisation gibt , dann ist auch dies eine umstrittene Ressource. Wenn es E / A gibt, ist dies eine umstrittene Ressource.

Sie werden nie eine N x -Beschleunigung sehen, wenn Sie von 1 auf N Threads wechseln. Dies ist nicht möglich, da alles in der CPU letztendlich eine gemeinsam genutzte Ressource ist, bei der es zu Konflikten kommen wird.

Es gibt viele Faktoren, die Sie daran hindern, die volle lineare Beschleunigung zu erreichen. Sie gehen davon aus, dass die Datenbank, der Server, auf dem die Datenbank ausgeführt wird, das Netzwerk, das sie mit dem Client verbindet, der Clientcomputer, das Betriebssystem und die Treiber auf beiden Seiten, das Speichersubsystem, die Festplatten-E / A und alles dazwischen kann nur 20-mal schneller sein, wenn Sie von 1 auf 20 Threads wechseln.

Zwei Wörter: Träume weiter.

Jeder dieser Engpässe muss Sie nur um einige Prozent verlangsamen, dann ist das Gesamtergebnis so etwas wie das, was Sie sehen.

Ich bin sicher, Sie können es optimieren, um es ein bisschen besser zu skalieren, aber erwarten Sie keine Wunder.

Aber eine Sache, nach der Sie suchen könnten, ist die gemeinsame Nutzung von Cache-Zeilen. Greifen Threads auf Daten zu, die den von anderen Threads verwendeten Daten sehr nahe kommen? Wie oft können Sie dies vermeiden?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top