Laden...

Threads/CPU Auslastung: Warum wird das Durchsuchen der Datei durch weitere Threads nicht schneller?

Erstellt von Gnozo vor 10 Jahren Letzter Beitrag vor 10 Jahren 3.428 Views
G
Gnozo Themenstarter:in
141 Beiträge seit 2011
vor 10 Jahren
Threads/CPU Auslastung: Warum wird das Durchsuchen der Datei durch weitere Threads nicht schneller?

Hallo Forum,

Ich habe eine Verarbeitung, welche sehr rechenintensiv ist und daher lange dauert. Um möglichst viel aus dieser Zeit rauszuholen habe ich mehrere Threads erstellt, welche alle paralell arbeiten.

Mal angenommen, ich habe 3 Threads, welche alle eine eigene Textdatei auf Schlüsselwörter durchsuchen.

Meine CPU hat 4 logische Kerne. Während der Verarbeitung der Textdateien läuft der CPU mit durschnittlichen 25% Auslastung.

Ich frage mich hierbei, warum er die anderen 75% nicht nutzt. Gibt ein einzelner Thread nicht mehr her oder regelt Windows dies intern, sodass dem Anwender noch genug Power übrig bleibt um andere Sachen zu erledigen?

Kann man steuern, dass ein Thread mehr "Power" bekommt? Das System soll sich ausschließlich auf die Verarbeitung konzentrieren und möglichst alle Ressourcen, sofern nicht reserviert, benutzen.

Oder gibt ein Thread einfach nicht mehr Power her und ich sollte mehr Threads paralell startet um die beste Auslastung zu bekommen? (Lieb wären wir Werte zwischen 80 und 90%)

Grüße
Gnozo

709 Beiträge seit 2008
vor 10 Jahren

Hallo Gnozo,
ich könnte mir vorstellen, dass hier die Festplatte ganz gut als Bremse funktioniert.
Bei gleichzeitigen Zugriffen auf verschiedene Dateien wird dort auch viel hin und hergesprungen.

Dass es eine Grenze für Maximallasten gibt, ist mir nicht bekannt.

Gruß
pinki

5.658 Beiträge seit 2006
vor 10 Jahren

Hi Gnozo,

vorausgesetzt, du hast dein Programm als Release kompiliert und außerhalb von VisualStudio gestartet, und die Abarbeitung des Programm wird nie durch Zugriff auf die Festplatte oder das Netzwerk unterbrochen, dann sollte man 100% Auslastung der Prozessorkerne erreichen. In deinem Fall könnte z.B. wie schon von pinki gesagt, die eigentliche Routine darauf warten, daß Daten aus der Datei gelesen werden. Währenddessen ist die CPU dann nicht ausgelastet.

Christian

Weeks of programming can save you hours of planning

G
Gnozo Themenstarter:in
141 Beiträge seit 2011
vor 10 Jahren

Hallo,

Es ist ein Service, welcher als Release kompiliert und fertig installiert ist.

Das mit der Festplatte kann durchaus Sinn ergeben, da die Last auch manchmal auf volle 100% geht, was demnach logisch klingt, weil in der Zeit die Festplatte dann nicht beschäftigt ist und die CPU wieder ordentlich Dampf geben kann.

Also wäre wohl eine Platte mit hoher Lese und Schreibgeschwindigkeit von Vorteil... Stichwort SSD was?

Gruß
Gnozo

16.842 Beiträge seit 2008
vor 10 Jahren

Von lokalen Festplatten nicht parallel lesen/schreiben (egal ob SSD oder HDD) - sowas nur bei Windows Shares, die extern liegen.
Je nachdem, was Du mit den Dateien machst, auf System.IO verzichten und direkt die Win32 API verwenden.

Bei sowas auch mal TPL Pipelining anschauen.

G
Gnozo Themenstarter:in
141 Beiträge seit 2011
vor 10 Jahren

Danke für die Tipps.

Wie schon von Abt erkannt, benutze ich den IO-Namespace. Werde mich mal in Win32 API einarbeiten und schauen, ob dies den gewünschten Performance Schub bringt.

Gruß
Lukas

16.842 Beiträge seit 2008
vor 10 Jahren

Wenn du die Dateien schon hast und nur liest dann brauchst den Win32 Umweg nicht machen.
Das lohnt sich nur beim Suchen bzw. bei Metadaten.

Ansonsten hab ich noch den Pipeline-Link gepostet.
Der Flaschenhals wird aber immer die HDD sein; in 99% der Fälle - egal wie Du das angehst.

Was sich lohnt ist die Dateien entweder in den RAM zu laden, oder in eine RAM-Disk.
Aber auch nicht bei jeder Größe.

849 Beiträge seit 2006
vor 10 Jahren

Hallo,

je nachdem was Du mit den Dateien machst würd es vllt. auch Sinn machen sie am Anfang ganz in den RAM zu laden.

*Ups letzten Satz von Abt hab ich wohl überlesen*

1.361 Beiträge seit 2007
vor 10 Jahren

Hi Gnozo,

wenn die Festplatte der Flaschenhals ist und sich deine CPUs langweilen, dann solltest du über eine Kompression nachdenken.
Gzip und co haben selbst einen zu geringen Durchsatz, aber spezialisierte Kompressoren wie LZ4, Snappy oder Blosc sind hervorragend geeignet.

Irgendwie müssen deine Daten ja auf die Platte gekommen sein. Hier einfach direkt komprimiert abspeichern (sollte auch Zeit sparen, da sicherlich auch hier die Festplatte der Flaschenhals ist).
Und dann beim Einlesen on-the-fly entpacken. Etwas mehr Arbeit für die CPU (die bei dir eh nicht ausgelastet ist), aber der Durchsatz erhöht sich drastisch, weil die Festplatte nur noch einen Bruchteil so viel zu tun hat!

Natürlich musst du den Kompressionsgrad passend einstellen, damit das Dekomprimieren nicht doch zum Flaschenhals wird. Aber so schnell sollte das nicht passieren.

PS: Je nachdem, ob du die Dateien mehrfach durchsuchen musst, könntest du vielleicht auch einen Index oder sonstige cleverere Datenstrukturen aufbauen um das Suchen an sich zu beschleunigen, damit nicht sequentiell durchgegangen werden muss.

beste Grüße
zommi

G
Gnozo Themenstarter:in
141 Beiträge seit 2011
vor 10 Jahren

Hallo nochmal,

Danke für eure Ratschläge. Ich habe mir das alles etwas genauer angeschaut. Mit einem Profiler, Logs geführt und ausgewertet, die CPU und Festplatten Last untersucht und habe irgendwie den Verdacht, dass die CPU immer nur an einem Thread arbeitet.

Ich starte 3 Threads, wovon scheinbar nur einer arbeitet. Mal bekommt Thread1 bisschen Dampf, dann mal Thread3 und Thread1 wird auf eis gelegt. Also im Prinzip scheint dann quasi immer nur einer zu Arbeiten.

Getestet habe ich dies, dass ich das Programm einmal mit 3 Threads loslaufen habe und einmal mit nur einem Thread. Ein Thread brauch genau so lange, wie 3 Threads. Ich bin mir aber sicher, dass die Threads alle arbeiten, wenn sie gestartet sind, da jeder Thread ein eigenes Log schreibt.

Ich starte die Threads mittels diesem Code:


                for (int i = 0; i < (Convert.ToInt32(PropertyGrid.ThreadCount)); ++i)
                {
                    WorkingThreads[i] = new System.Threading.Thread(ReadOCROutput);                    
                    WorkingThreads[i].Name = "WorkingThread_" + i;
                    WorkingThreads[i].Priority = System.Threading.ThreadPriority.Highest;
                    WorkingThreads[i].IsBackground = true;
                    WorkingThreads[i].Start();
                }

Auch habe ich ein Verhalten beobachtet, welches mir auch nicht ganz Schlüssig ist. Ich habe mein Programm auf einer Viruellen Maschiene installiert und verschiedene Konfigurationen probiert.

Die VM hat 1 Kern zugewiesen bekommen: Bei 3 Threads liegt die Last bei 100%
Die VM hat 2 Kerne zugewiesen bekommen: Bei 3 Threads liegt die Last bei 50%
Die VM hat 4 Kerne zugewiesen bekommen: Bei 3 Threads liegt die Last bei 25%
Zwischendurch springt der Wert auch mal auf die vollen 100%.

Diesen Werten entnehme ich, dass scheinbar nur 1 Kern wirklich beschäftigt ist. Ich würde ungerne den Threads feste Kerne zuweisen und das lieber von Windows regeln lassen. Im Taskmanager sehe ich, dass jeder Kern deutlich ausgelastet ist und nicht bei 0-2% liegt sondern die Werte dort extrem schwanken(2-70%).

Ich kann mir dieses Verhalten beim besten Willen nicht erklären und hoffe, ihr könnt mir dabei weiterhelfen.

Der Verdacht mit der Festplatte besteht noch, da ich das Programm dank Urlaubes noch nicht daraufhin anpassen konnte. Dort werde ich mir nochmal die Lösungen anschauen und versuchen einzubauen.

Vielleicht sollte ich noch erwähnen, dass ich das Warteschlangen-Konstrukt von Abt verwende. Leider noch die .NET 3.5 Version da 4.0 noch nicht in Frage kommen kann. C# Warteschlangen von Abt

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo Gnozo,

Der Verdacht mit der Festplatte besteht noch, da ich das Programm dank Urlaubes noch nicht daraufhin anpassen konnte. Dort werde ich mir nochmal die Lösungen anschauen und versuchen einzubauen.

das solltest du als erstes tun, denn der Verdacht ist berechtigt und solange er nicht ausgeräumt ist, ist alles weitere unnötige Spekulation. Die Situation, die du jetzt beschreibst, entspricht der am Anfang geschilderten und deshalb können wir auch nicht mehr oder anderes sagen, als bisher schon getan.

herbivore

4.221 Beiträge seit 2005
vor 10 Jahren

WO genau rufst Du die intensive Verarbeitung auf ?

Vielleicht hast Du diese ja innerhalb des Lock im Consume aufgerufen... dann müssten alle anderen Threads warten... es wäre immer nur 1 am werkeln...

Ansonsten prüfe mal ob Du irgendwo noch weitere Critical Sections hast an welchem sich die Threads stauen.

Wollte mit meinem Post nur darauf hinweisen, dass nicht nur die Festpladde der Flaschenhals sein muss...

Gruss
Programmierhans

Früher war ich unentschlossen, heute bin ich mir da nicht mehr so sicher...

G
Gnozo Themenstarter:in
141 Beiträge seit 2011
vor 10 Jahren

Hi Leute,

Also ich habe gestern die Festplatte als Flaschenhals ausschließen können und bin darauf gestoßen, dass, wie von Programmierhans erwähnt, ein wichtiger Funktionsaufruf leider in dem lock() passierte....

Dummer Fehler meinerseits, entschuldigt, dass ich deswegen so einen Wirbel gemacht habe 😃

Gruß
Lukas