Forum: PC-Programmierung [C#] CPU Auslastung bei Threading


von Draco (Gast)


Angehängte Dateien:

Lesenswert?

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
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Data;
5
using System.Drawing;
6
using System.Linq;
7
using System.Text;
8
using System.Windows.Forms;
9
10
using System.Threading;
11
12
namespace Thread_Test
13
{
14
    public partial class Form1 : Form
15
    {
16
17
        
18
        public Form1()
19
        {
20
            InitializeComponent();
21
22
            Thread Thread_one = new Thread(fuc_Thread_one);
23
            Thread Thread_two = new Thread(fuc_Thread_two);
24
            Thread Thread_three = new Thread(fuc_Thread_three);
25
26
            Thread_one.Start();
27
            Thread_two.Start();
28
            Thread_three.Start();
29
        }
30
31
        private void button1_Click(object sender, EventArgs e)
32
        {Environment.Exit(0);}
33
34
        public void fuc_Thread_one()
35
        {
36
            bool done = false;
37
            while (!done)
38
            {
39
40
            }
41
        }
42
43
        public void fuc_Thread_two()
44
        {
45
            bool done = false;
46
            while (!done)
47
            {
48
49
            }      
50
        }
51
52
        public void fuc_Thread_three()
53
        {
54
            bool done = 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?!

von Peter II (Gast)


Lesenswert?

Draco schrieb:
> Hat da jemand Vorschläge?!

einfach ein sleep einbauen.

Jeder Thread lastet eine Kern zu 100% aus.

von Der Andere (Gast)


Lesenswert?

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.

von Draco (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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?

von Der Andere (Gast)


Lesenswert?

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

von Draco (Gast)


Angehängte Dateien:

Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

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.

von asdfsdf (Gast)


Lesenswert?

my.application.doevents einfügen in die Schleife

von Peter II (Gast)


Lesenswert?

asdfsdf schrieb:
> my.application.doevents einfügen in die Schleife

wozu? Das macht man nur ein MainThreads aber nicht in andere Threads.

von Karl Käfer (Gast)


Lesenswert?

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.

von EVP (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.