Ich habe hier ein "kleines" Problem. Was ja im Grunde eigentlich logisch
ist, wenn man mal die Randbedingungen betrachtet.
Ich habe eine Anwendung mit drei Threads, alle drei laufen
gleichzeichtig - jedoch steigt dabei die CPU Auslastung extrem hoch.
Hier mal ein extrem vereinfachtes Beispiel von mir:
1
usingSystem;
2
usingSystem.Collections.Generic;
3
usingSystem.ComponentModel;
4
usingSystem.Data;
5
usingSystem.Drawing;
6
usingSystem.Linq;
7
usingSystem.Text;
8
usingSystem.Windows.Forms;
9
10
usingSystem.Threading;
11
12
namespaceThread_Test
13
{
14
publicpartialclassForm1:Form
15
{
16
17
18
publicForm1()
19
{
20
InitializeComponent();
21
22
ThreadThread_one=newThread(fuc_Thread_one);
23
ThreadThread_two=newThread(fuc_Thread_two);
24
ThreadThread_three=newThread(fuc_Thread_three);
25
26
Thread_one.Start();
27
Thread_two.Start();
28
Thread_three.Start();
29
}
30
31
privatevoidbutton1_Click(objectsender,EventArgse)
32
{Environment.Exit(0);}
33
34
publicvoidfuc_Thread_one()
35
{
36
booldone=false;
37
while(!done)
38
{
39
40
}
41
}
42
43
publicvoidfuc_Thread_two()
44
{
45
booldone=false;
46
while(!done)
47
{
48
49
}
50
}
51
52
publicvoidfuc_Thread_three()
53
{
54
booldone=false;
55
while(!done)
56
{
57
58
}
59
}
60
}
61
}
Im Grunde macht er ja nix, außer in jedem Thread die schleifen zu
durchlaufen. Was ja, im Grunde, auch zu einer gewissen CPU Last führt,
da er ja so schnell wie möglich die Schleife durchläuft, die Bedingung
(done) prüft und weiter läuft....
Diese kleine Anwendung jedoch lastet die CPU zu 75% aus. Gibt es
Möglichkeiten soetwas zu entschärfen und die Threads zu "verlangsamen"?
Im Grunde habe ich auch eine bestätigung, das das Threading
Core-abhängig ist. Die Maschine auf der ich hier arbeite ist ein i5 mit
4-Kernen ohne Hyperthreading. Schalte ich nur zwei Threads an, steigt
die Auslastung auch nur auf 50%. Lasse ich diese Anwendung auf meinem i7
laufen (4-Kerne + HT) dann ist das Ergebnis auch abhängig der Kernzahlen
(4 Threads -> 50%, 2 Threads -> 25%).
Hat da jemand Vorschläge?!
Draco schrieb:> Im Grunde habe ich auch eine bestätigung, das das Threading> Core-abhängig ist. Die Maschine auf der ich hier arbeite ist ein i5 mit> 4-Kernen ohne Hyperthreading. Schalte ich nur zwei Threads an, steigt> die Auslastung auch nur auf 50%. Lasse ich diese Anwendung auf meinem i7> laufen (4-Kerne + HT) dann ist das Ergebnis auch abhängig der Kernzahlen> (4 Threads -> 50%, 2 Threads -> 25%).
Das ist Rechnen 4. Klasse.
Du lässt 3 Threads parallel so schnell wie möglich arbeiten, ohne IO
also was erwartest du?
Was ist das Ziel? Wenn noch mehr auf dem Rechner läuft wird es schon von
alleine langsamer, für CPU Leerlauf gibt es keinen Bonus.
Statt sleeps kannst du auch einfach nur einen oder zwei Threads laufen
lassen, dann wird es auch langsamer.
Peter II schrieb:> einfach ein sleep einbauen.>> Jeder Thread lastet eine Kern zu 100% aus.
Sleep wäre ne Möglichkeit. Werde da mal probieren.
Der Andere schrieb:> Das ist Rechnen 4. Klasse.> Du lässt 3 Threads parallel so schnell wie möglich arbeiten, ohne IO> also was erwartest du?>> Was ist das Ziel? Wenn noch mehr auf dem Rechner läuft wird es schon von> alleine langsamer, für CPU Leerlauf gibt es keinen Bonus.>> Statt sleeps kannst du auch einfach nur einen oder zwei Threads laufen> lassen, dann wird es auch langsamer.
Das ist mir völlig bewusst :-) Und wenn du 1+1+1+1 erst in der vierten
Klasse hattest, hast du bestimmt in der ersten nur Klatschen und Tanzen
gehabt. Denn ich oder meine Tochter hatte dies bereits in der ersten.
Es geht nicht darum das ich 1+1 rechne, sondern darum das mich die
Tatsache verblüfft das jeder Thread einen Core nutzt. Weniger verblüfft
hätte mich die Tatsache, das eine einzelne "While-Done" die CPU zu 100%
auslastet.
Die Hauptanwendung, in der ich das Problem feststellte, benötigt aber
drei Threads, sodass ich nicht einfach sagen kann "Ach egal, mach ich
bloß". Sie arbeitet asynchron nach dem EVA Prinzip. Synchronisieren kann
ich die Anwendung nicht, da auf jeden Fall E und A kontinuierlich laufen
müssen, nicht mit vollem Takt, aber dennoch gleichmäßig.
Deswegen ist ein Sleep wahrscheinlich die beste Wahl der Mittel aktuell.
Draco schrieb:> Synchronisieren kann> ich die Anwendung nicht, da auf jeden Fall E und A kontinuierlich laufen> müssen, nicht mit vollem Takt, aber dennoch gleichmäßig.
was machen die Threads genau? Warum dürfen sie nicht so schnell laufen
wie sie wollen? Wenn sie auf andere dinge warten, dann brauchen sie auch
keine CPU-Zeit wenn man es richtig macht.
> Deswegen ist ein Sleep wahrscheinlich die beste Wahl der Mittel aktuell.
eigentlich nicht. Sleep ist selten eine gute Lösung. Man will ja schnell
mit etwas fertig werden.
> Es geht nicht darum das ich 1+1 rechne, sondern darum das mich die> Tatsache verblüfft das jeder Thread einen Core nutzt.
das ist doch sinn des ganzen
> "While-Done" die CPU zu 100%> auslastet.
was soll sie denn sonst noch nebenbei machen können?
Draco schrieb:> Es geht nicht darum das ich 1+1 rechne, sondern darum das mich die> Tatsache verblüfft das jeder Thread einen Core nutzt.
Genau dafür gibt es multithreading.
Draco schrieb:> Weniger verblüfft> hätte mich die Tatsache, das eine einzelne "While-Done" die CPU zu 100%> auslastet.
Wenn das so einfach ginge, dann hättest du mindestens ein
Softwarepatent. Das würde alle anderen hier verblüffen
Draco schrieb:> Sie arbeitet asynchron nach dem EVA Prinzip. Synchronisieren kann> ich die Anwendung nicht, da auf jeden Fall E und A kontinuierlich laufen> müssen, nicht mit vollem Takt, aber dennoch gleichmäßig.
Mit einem Sleep wirst du nichts aber auch gar nichts gleichmäßig laufen
lassen können.
Du widersprichst dir selbst, entweder asynchron oder "gleichmäßig"
Wenn die Prozesse irgendwo "gleichmäßig" sein müssen, dann musst du sie
synchronisieren. Mittel dazu gibt es in allen ernstzunehmenden
Programmiersprachen, du musst sie halt verwenden.
Peter II schrieb:> was machen die Threads genau? Warum dürfen sie nicht so schnell laufen> wie sie wollen? Wenn sie auf andere dinge warten, dann brauchen sie auch> keine CPU-Zeit wenn man es richtig macht.
Genau so ist es. Und fürs Daumendrehen wird die CPU nicht bezahlt.
Draco schrieb:> Denn ich oder meine Tochter hatte dies bereits in der ersten.
Wer jetzt; Du oder deine Tochter :-)
Dafür dass du Hilfe brauchst bist du ganz schön nassforsch.
Und Prozentrechnung hatte ich ziemlich sicher nicht in der 1. Klasse:
Draco schrieb:> zu 75% aus
Peter II schrieb:> was machen die Threads genau? Warum dürfen sie nicht so schnell laufen> wie sie wollen? Wenn sie auf andere dinge warten, dann brauchen sie auch> keine CPU-Zeit wenn man es richtig macht.
E - ließt einen Netzwerkstream ein, dieser Thread ist nicht kritisch was
die Auslastung angeht, da der Thread sowieso gestoppt wird sobald kein
neuer Stream verfügbar ist. Dieser Stream jedoch kommt in immer
"ungewissen" Abständen von ca. 10ms - 150ms.
V - Berechnet die Daten von E, sowie eine - (in den Pausen der
Übermittlung) eine Zwischenwertberechnung.
A - Das ist die einzigste Zeitkritische Anwendung. Muss die Daten
regelmäßig über UART rausschieben. Zeitkritisch heißt hier aber nicht
das er sie schnell hintereinander - sondern gleichmäßig bereit stellt.
Dabei spielt es keine Rolle ob V schon mit der Berechnung fertig ist und
bereits neue Daten vorliegen, sollten nicht - werden die alten weiter
benutzt. Hier muss aber nicht jede 5µs ne Nachricht raus. Hier reicht
mir, wenn alle 10ms ein Paket das Zuhause verlässt - aaaaber gleichmäßig
:D .
Das schöne, habe ich gerade festgestellt, ist - das ich den Thread
direkt in Sleep legen lassen kann. Also, nicht wie ich mir das dacht
(wie zum bsp AVR etc...) Das das System ne "Pause" ala "nop" macht,
sondern der Thread ruhend geschickt wird.
Ein Thread.Sleep von nur 1ms (in V und A) hat schon so ziemlich alle
Sorgen behoben und reduziert die Auslastung von meiner Hauptanwendung
von 56% auf 4% runter. In der Beispielanwendung oben reduziert sie sich
auf 0% CPU Zeit.
Draco schrieb:> E - ließt einen Netzwerkstream ein, dieser Thread ist nicht kritisch was> die Auslastung angeht, da der Thread sowieso gestoppt wird sobald kein> neuer Stream verfügbar ist. Dieser Stream jedoch kommt in immer> "ungewissen" Abständen von ca. 10ms - 150ms.
dann sollte dieser auch keine CPU zeit brauchen
> V - Berechnet die Daten von E, sowie eine - (in den Pausen der> Übermittlung) eine Zwischenwertberechnung.
dann sollte er ohne CPU-Last ja warten ( z.b. mit einen Event )
> A - Das ist die einzigste Zeitkritische Anwendung. Muss die Daten> regelmäßig über UART rausschieben. Zeitkritisch heißt hier aber nicht> das er sie schnell hintereinander - sondern gleichmäßig bereit stellt.> Dabei spielt es keine Rolle ob V schon mit der Berechnung fertig ist und> bereits neue Daten vorliegen, sollten nicht - werden die alten weiter> benutzt. Hier muss aber nicht jede 5µs ne Nachricht raus. Hier reicht> mir, wenn alle 10ms ein Paket das Zuhause verlässt - aaaaber gleichmäßig> :D .
da UART das Langsamste ist, wartet er eh ständig.
> Ein Thread.Sleep von nur 1ms (in V und A) hat schon so ziemlich alle> Sorgen behoben und reduziert die Auslastung von meiner Hauptanwendung> von 56% auf 4% runter.
dann hast du irgendetwas falsch gemacht. Es gibt keine Grund für eine
Sleep. Das ganze kann man ohne schreiben und dann ist vermutlich deine
Last noch viel geringer.
Draco schrieb:> Es geht nicht darum das ich 1+1 rechne, sondern darum das mich die> Tatsache verblüfft das jeder Thread einen Core nutzt. Weniger verblüfft> hätte mich die Tatsache, das eine einzelne "While-Done" die CPU zu 100%> auslastet.
Wenn es Dicht nicht wundert, daß eine while-Schleife einen Core zu 100%
auslastet, dürfte es Dich eigentlich auch nicht wundern, daß drei dieser
Schleifen drei Cores auslasten. Aus Systemsicht sieht das so aus, daß da
drei Threads rennen, von denen jeder möglichst viel Leistung braucht --
darum verteilt das System diese Threads auf die vorhandenen Cores.
> Die Hauptanwendung, in der ich das Problem feststellte, benötigt aber> drei Threads, sodass ich nicht einfach sagen kann "Ach egal, mach ich> bloß". Sie arbeitet asynchron nach dem EVA Prinzip. Synchronisieren kann> ich die Anwendung nicht, da auf jeden Fall E und A kontinuierlich laufen> müssen, nicht mit vollem Takt, aber dennoch gleichmäßig.>> Deswegen ist ein Sleep wahrscheinlich die beste Wahl der Mittel aktuell.
Ich kenne mich mit Windows nicht aus, aber unter Linux gibt es select(),
poll() und epoll(). Diesen Funktionen werden Arrays von Dateihandlern
übergeben, und wenn bei einem der Dateihandler ein I/O-Ereignis ansteht,
kommen sie zurück und übergeben den betreffenden Dateihandler. Solange
kein I/O-Ereignis ansteht, warten diese Funktionen, ohne die CPU zu
belasten -- und damit könntest Du Deine Anwendung ohne Threads schreiben
oder die Threads erst dann starten, wenn ein I/O-Ereignis zu verarbeiten
ist. Eine solche Architektur wird deutlich weniger CPU-Last erzeugen und
auch unter hoher paralleler Last viel besser performen.
Unter Windows gibt es da wohl ähnliche Techniken wie I/O Completion
Ports, Asynchronous Procedure Calls und Overlapped I/O. YMMV.
Das ist doch ein Paradebeispiel für das allgegenwärtige Erzeuger-
Verbraucher-Problem. Falls du oder deine Tochter das nicht sowieso
schon in der 1. Klasse gelernt haben sollten, kannst du dazu in
jedem Grundlagenbuch zur nebenläufigen Programmierung jede Menge
Lösungsvorschläge finden.