Frage zu Multithreading!
-
Nein, es hat nicht jeder Thread seine eigene Methode.
Aber jeder Thread hat eigene Parameter und lokale Variablen.D.h. du musst nicht für jeden Thread eine Kopie der Methode machen.
-
werkla4 schrieb:
Sollte ich für jeden Thread eine Eigene Methode erstellen? Die Frage ist: "Wenn ein Thread schon in der Methode drin ist und ein zweiter Thread diese auch grad verwendet, Nicht das der 2.Thread mit falschen Parametern startet, nur weil schon Thread 1 ein paar Parameter geändert hat und noch in dieser Methode drin ist?
Oder gibt es da keine Komplikationen, da jeder Thread seine "eigene" Methode nutzt?eine funktion mit lokalen variablen legt diese am stack ab, und da jeder thread seinen eigenen stack hat, hat auch jede funktion ihre eigenen kopien der variablen.
anders ist das natürlich bei globalen variablen bzw. ganz allgemein variablen, die nicht funktions-lokal sind.int x=0;
void foo()
{
int a=3,b=0; <-- lokale Kopien
++x; <-- global
}void bar()
{
int a=3,b=0; <-- lokale Kopien
b=a*x; <-- hängt auch vom globalen zustand ab
}der code war jetzt C, aber du kannst dir leicht denken, wie das ganze in C# auszusehen hat.
-
Jo Danke, also das mit lokal und global ist ja klar (Grundwissen). Dann danke ich dir für die Auskunft auf meine Frage.
-
werkla4 schrieb:
Jo Danke, also das mit lokal und global ist ja klar (Grundwissen).
Echt? Wieso fragst du dann?
-
int[] Zahlenkombination = new int[2] { 0, 0 }; bool Berechnen = true; Thread t1 = new Thread(() => Fertig()); t1.Start(); Thread t2 = new Thread(() => Fertig()); t2.Start(); while (Berechnen) { if (Raus(Zahlenkombination, Min.Length)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, Min.Length); if (Berechnen) { t1.Join(); t1 = new Thread(() => Berechnung(Zahlenkombination,1)); t1.Start(); } if (Raus(Zahlenkombination, Min.Length)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, Min.Length); if (Berechnen) { t2.Join(); t2 = new Thread(() => Berechnung(Zahlenkombination,2)); t2.Start(); } } t1.Join(); t2.Join(); // Fertig
In KomboErhöhen werden Zahlenkombinationen hochgezählt z.B.:
0,1
0,2
0,3
0,4
0,5
0,6
0,7
0,8
0,9
0,10
...
Fertig (Dies Ermittelt Raus())Im Einzelschritt Debuggung funktioniert alles tadellos! Wahrscheinlich da er beim langsamen ausführen des Programms schon lange fertig ist. Aber in kompilierter Form führt er es nicht ordentlich aus
als Test schreiben mir die Methoden die Zahlenkombinationen in eine csv.datei
Leider kommt dies heraus beim Ausführen des Programms
Thread1:0,1;0,3;0,4;0,6;0,7;0,8
Thread2:0,2;0,3;0,4;0,5;0,7;0,9Aber theoretisch möchte ich gerne das keine Zahlen doppelt sind! Es darf keine Zahl von Thread 1 in Thread 2 sein und andersherum! Aber es sollten alle Zahlenkombos bis zum Schluss gezählt dabei sein!
Jemand Tipps für mich?
P.s. Das mit dem Grundwissen hatte ich nicht so gemeint! Sorry! Sonst hätte ich ja nicht hier Nachgefragt.
-
Ja das sieht wild aus. Aber zeige erstmal die restlichen Methoden.
Hast Du Dir mal das Tutorial angesehen, v.a. die Synchonisations-Mechanismen?
-
werkla4 schrieb:
Im Einzelschritt Debuggung funktioniert alles tadellos! Wahrscheinlich da er beim langsamen ausführen des Programms schon lange fertig ist. Aber in kompilierter Form führt er es nicht ordentlich aus
Der Debugger zeigt dir vermutlich den Ablauf den Threads der Main. Wenn du einen Schritt weiter klickst, dann vergeht eine laengere Zeit, in der die anderen Threads ausgefuehrt werden. Dadurch zwingst du dem System eine Reihenfolge auf!
Es ist lobenswert, dass du das Ganze lernst, jedoch hast vermutlich den Kern wirklich verstanden. Du kannst naemlich kein paralleles System ueberwachen, wenn du dir nur einen Strang anschaust.
Wie das zustande kommt koenntest du dir veranschaulichen, indem du Ausgaben ueber die Konsole machst.
Beispiel: Wenn der Main Thread einen Thread startet machst du eine Ausgabe und jedes mal, wenn der Thread dann ausgefuehrt wird macht er auch eine Ausgabe. Damit wuerdest du sehen, in welcher Reihenfolge es ablaeuft (die Reihenfolge kann bei jedem Programmstart variieren!!!).
Aber schauen wir uns kurz an, was bei dir schief laeuft. Nehmen wir dein Ergebnis:
werkla4 schrieb:
Leider kommt dies heraus beim Ausführen des Programms
Thread1:0,1;0,3;0,4;0,6;0,7;0,8
Thread2:0,2;0,3;0,4;0,5;0,7;0,9Der Hauptthread legt in Zeile 1 ein Objekt an.
In Zeile 15 und 16 wird die Referenz auf das Objekt an einen neuen Thread gegeben und dieser wird gestartet.
Nun wechselt das OS den Thread und dein erster Thread kommt dran, liest den Wert im Objekt und gibt diesen aus. Danach stirbt er und der Hauptthread kommt wieder dran.
Der Hauptthread veraendert den Wert im Objekt und macht das ganze Spiel mit Thread 2 noch einmal. (Das ist deine zweite Ausgabe.)Nun veraendert der Hauptthread wieder den Wert und startet diesmal beide Threads, bevor er die CPU abgiebt und die anderen beiden Threads dran laesst. Die lesen das zur gleichen Zeit aus dem selben Objekt und entnehmen den selben Wert. Und da haben wir dann deinen Fehler.
Dein Hauptproblem ist, dass du einen sequentiellen Ablauf parallel loesen moechtest und das wird solange schief gehen, solange du die parallelen Ablaeufe nicht dazu zwingst sequentiell zu arbeiten.
-
int[] Zahlenkombination = new int[2] { 0, 0 }; bool Berechnen = true; int[] Kombo1, Kombo2; Thread t1 = new Thread(() => Fertig()); t1.Start(); Thread t2 = new Thread(() => Fertig()); t2.Start(); while (Berechnen) { if (!t1.IsAlive) { if (Raus(Zahlenkombination, Min.Length)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, Min.Length); if (Berechnen) // Thread1 { t1.Abort(); t1.Join(); Kombo1 = new int[] { Zahlenkombination[0], Zahlenkombination[1] }; t1 = new Thread(() => Berechnung(Kombo1, 1)); t1.Start(); } } if (!t2.IsAlive) { if (Raus(Zahlenkombination, Min.Length)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, Min.Length); if (Berechnen) // Thread2 { t2.Abort(); t2.Join(); Kombo2 = new int[] { Zahlenkombination[0], Zahlenkombination[1] }; t2 = new Thread(() => Berechnung(Kombo2, 2)); t2.Start(); } } Thread.Sleep(10); }
-
Kommt drauf an... Wenn die Aufgabenstellung war möglichst maximalen Schwachsinn mit Threads zu machen, dann ist das schon eine gute Lösung.
Ansonsten würde es helfen zu wissen welche Aufgabe Du versuchst zu lösen, dann könnte man auch sagen wie man es richtig macht. Der Code den Du zuletzt gepostet hat ist jedenfalls alles andere als sinnvoll. So sollte man z.B. nie Thread.Abort() verwenden, weil das zu beliebigem Fehlverhalten des Codes führen kann der gerade in dem Thread ausgeführt wird.
-
Abort() und Join() habe ich soeben entfernt!
Es wird ja schon bei ISALIVE kontrolliert ob dieser Thread fertig ist oder nicht.Zielsetzung war:
Wie kann ich diesen Prozess in mehrere Threads aufteilen um einerseits meine Rechnerleistung voll auszuschöpfen
und schneller mit dieser einen Aktion fertig zu werden!KomboErhöhen() zählt wie eine Art Schleife die Zahlen hoch!
In dieser Schleife werden extrem viele Berechnungen ausgeführt und dauern auch extrem lang.
Nur alleine den Main-Thread nacheinander berechnen zu lassen dauert zu lang!
Die Idee war also: Sobald der Main-Thread die Schleife hochgezählt hat Gebe ich diese Aufgabe dem ersten Thread; Sobald der Main-Thread wieder die Schleife erhöht gebe ich diese dem 2.Thread wenn der 1.Thread noch nicht fertig ist!...
Und speichere die Daten dann jeweils dem Thread entsprechend in eine eigene datei.
-
werkla4 schrieb:
Zielsetzung war:
Wie kann ich diesen Prozess in mehrere Threads aufteilen um einerseits meine Rechnerleistung voll auszuschöpfen
und schneller mit dieser einen Aktion fertig zu werden!Das haengt stark von deinem Problem ab. Manche Probleme lassen sich garnicht so zerlegen. Daher solltest du wissen, ob sich die Aufgabe ueberhaupt sinnvoll parallelisieren laesst. Wenn du das nicht machst, dann bekommst du schnell andere Effekte.
Merk dir am Besten zwei Gruende fuers Parallelisieren:
1. Du hast Aufgaben ala GUI und richtige Anwendung, bei denen du dich z.B. nicht darauf konzentrieren moechtest, ob du gerade die Berechnung fortsetzen moechtest oder kurz die GUI neu zeichnen musst (zwei Threads und die Organisation wird leichter, jedoch muessen beide Teile synchronisiert werden).
2. Du hast unabhaengige Programmteile, die sich nicht beeinflussen.Beim letzteren Teil kannst du wirklich Geschwindigkeit gewinnen.
werkla4 schrieb:
Nur alleine den Main-Thread nacheinander berechnen zu lassen dauert zu lang!
Diese Aussage stimmt mit einem weit verbreiteten Mythos ueberein.
Nur weil du mehr Kerne hast oder mehr Threads wird das Programm nicht schneller. Es gibt auch Szenarien, bei denen du bei sinnlosen Parallelisieren langsamere Programme bekommst. Du musst naemlich bedenken, dass die Threads auch verwaltet werden muessen und mit mehr Threads hat das Betriebssystem mehr zu tun und wenn dann noch die Threads schlecht synchronisiert werden, dann wird dein Programm ganz schnell mal langsamer.
-
werkla4 schrieb:
Wie kann ich diesen Prozess in mehrere Threads aufteilen um einerseits meine Rechnerleistung voll auszuschöpfen
und schneller mit dieser einen Aktion fertig zu werden!Ich habe Dich schonmal gebeten die anderen Methoden zu zeigen.
Fertig, Berechnung, KomboErhöhen
und wie sie heißen.werkla4 schrieb:
Die Idee war also: Sobald der Main-Thread die Schleife hochgezählt hat Gebe ich diese Aufgabe dem ersten Thread; Sobald der Main-Thread wieder die Schleife erhöht gebe ich diese dem 2.Thread wenn der 1.Thread noch nicht fertig ist!...
Producer-Consumer-Queue. Siehe Tutorial.
Irgendwie willst Du nicht wirklich Hilfe, oder?
-
werkla4 schrieb:
Es wird ja schon bei ISALIVE kontrolliert ob dieser Thread fertig ist oder nicht.
Das ist falsch. IsAlive prüft ob der Thread läuft oder nicht. mit "Fertig"-Sein hat das nichts zu tuen.
werkla4 schrieb:
Wie kann ich diesen Prozess in mehrere Threads aufteilen [...]
Wortklauberei, aber... Man teilet einen Prozess nicht in Threads auf. Threads laufen in einem Prozess...
werkla4 schrieb:
Die Idee war also: Sobald der Main-Thread die Schleife hochgezählt hat Gebe ich diese Aufgabe dem ersten Thread; Sobald der Main-Thread wieder die Schleife erhöht gebe ich diese dem 2.Thread wenn der 1.Thread noch nicht fertig ist!...
Der Gedankengang zeigt deutlich das Du noch nicht begriffen hast wie Threads funktionieren. Wie man es machen würde: Partitionieren und verteilen. (Oder wie Caesar sagte: Teilen und herrschen)
Also: Die Menge der Berechnungen in zwei Teilmengen zerlegen und jedem Thread eine dieser Teilmengen zur Abarbeitung geben die dieser dann selbstständig nacheinander berechnet.
werkla4 schrieb:
Und speichere die Daten dann jeweils dem Thread entsprechend in eine eigene datei.
Und hier holt dich dann Amdahl's law ein ein Festplattenzugriffe sequentiell sind...
-
int[] Zahlenkombination = new int[2] { 0, 0 }; bool Berechnen = true; int[] Kombo1, Kombo2; int AnzThreads = 2; int MaxZahl = 10; Thread t1 = new Thread(() => Fertig()); t1.Start(); Thread t2 = new Thread(() => Fertig()); t2.Start(); while (Berechnen) { if (AnzThreads >= 1) if (!t1.IsAlive) { if (Raus(Zahlenkombination, MaxZahl)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, MaxZahl); if (Berechnen) // Thread1 { Kombo1 = new int[] { Zahlenkombination[0], Zahlenkombination[1] }; t1 = new Thread(() => Berechnung(Kombo1, 1)); t1.Start(); } } if (AnzThreads >= 2) if (!t2.IsAlive) { if (Raus(Zahlenkombination, MaxZahl)) Berechnen = false; KomboErhöhen(ref Zahlenkombination, MaxZahl); if (Berechnen) // Thread2 { Kombo2 = new int[] { Zahlenkombination[0], Zahlenkombination[1] }; t2 = new Thread(() => Berechnung(Kombo2, 2)); t2.Start(); } } Thread.Sleep(100); } // Warte bis alle Threads fertig sind int AnzKontrolle = 0; bool ThreadsNichtFertig = true; do { int AnzFertigeThreads = 0; if (AnzThreads >= 1 && !t1.IsAlive) AnzFertigeThreads++; if (AnzThreads >= 2 && !t2.IsAlive) AnzFertigeThreads++; if (AnzFertigeThreads == AnzThreads) ThreadsNichtFertig = false; AnzKontrolle++; Thread.Sleep(1000); } while (ThreadsNichtFertig); //Fertig mit Berechnungen void Berechnung(int[] Zahlenkombination, int Thread_Nr) { string Ordnerpfad = @"C:\Users\KW\Desktop\Arbeit\TEST"; string CSV_ErgebnisPfad = Path.Combine(Ordnerpfad, "CSV_Thread" + Thread_Nr + ".csv"); StreamWriter Schreiber = new StreamWriter(CSV_ErgebnisPfad, true); // Dies will ich natürlich nicht berechnen aber als kurzes Beispiel!! Das eine Berechnung in eine CSV Datei geschrieben wird. Schreiber.WriteLine("Zahlenkombination: " + Zahlenkombination[0] + "_" + Zahlenkombination[1] + " = " + (Zahlenkombination[0] + Zahlenkombination[1]).ToString()); Schreiber.Close(); } void Fertig() { return; } void KomboErhöhen(ref int[] Zahlenkombination, int Max) { bool Geändert = false; if (Zahlenkombination[1] >= Max - 1) { Zahlenkombination[0]++; Zahlenkombination[1] = Zahlenkombination[0] + 1; Geändert = true; } if (!Geändert) { Zahlenkombination[1]++; if (Zahlenkombination[1] >= Max) { Zahlenkombination[0]++; Zahlenkombination[1] = Zahlenkombination[0] + 1; } } } bool Raus(int[] Zahlenkombination, int Max) { if (Zahlenkombination[0] >= Max - 1) return true; return false; }
-
Oder kann mir den jemand zeigen wie ein kleines richtiges Beispiel aussieht?
Vorraussetzung ist jeweils die Threads sollen aus einer Schleife heraus gebildet werden:int i=1;
bool Berechnen = true;while(Berechnen)
{
// i%2 ==1 Starte ersten Thread, i++// i%2 ==0 Starte zweiten Thread, i++
if(i>=10)
Berechnen=false;
}Leider habe ich nicht so viel Ahnung was da im Hintergrund eines Programm-Codes läuft aber leider benötige ich unbedingt diese Funktion (Multithreading zur besseren Auslastung meines Computers).
Wie wir alle Wissen: "Unser wichtigstes Gut ist Zeit (und Gesundheit) !".
-
In meinem Test mit dem letzten gesamten Code verspüre ich nur eine Verschnellerung des Programms wenn Thread.Sleep() mit in der Berechnungsmethode eingebaut ist! Ansonsten ist es bis jetzt noch nicht spürbar
Außer der CPU geht hoch...
-
Alter Schwede. Das ist der WTF-Code der Woche. Das ist völlig absurd und falsch was Du da machst.
Kannst Du mal eine Single-Thread-Lösung dessen posten, was Du eigentlich damit berechnen willst?
Oder Eingabe-Ausgabe-Beispiele aufzeigen?Das ist in der Form nicht zu reparieren und muss neu geschrieben werden. Wenn ich genau weiß was zu tun ist, finde ich übers WE bestimmt mal etwas Zeit. Vorausgesetzt da lässt sich überhaupt etwas parallelisieren. Bisher schreibst Du ja nur in Dateien und von aufwändigen Berechnungen sehe ich nichts.