Frage zu Multithreading!
-
Vielen dank für die antwort, es hat mir mehr verständnis in dieses thema gegeben. Da werde ich wohl join mit einbauen
Ist es auch möglich den threads(methode) parameter mitzugeben, so wie ich es versucht hatte?
Noch eine frage: Wenn mehrere threads zeitgleich laufen und auf der festplatte etwas abspeichern wollen, da gibt es hoffentlich keine komplikationen (bei evtl. überlappung), das abspeichern wird bestimmt einen nach den anderen erledigt...?
-
Sorry, erste frage hat sich ja in dem fall erledigt!
Aber wie ist das mit dem speichervorgang, zwecks festplatte? Werden diese speichervorgänge bestimmt nach und nach erledigt...!?
-
werkla4 schrieb:
Ist es auch möglich den threads(methode) parameter mitzugeben, so wie ich es versucht hatte?
Ja. Mit ParameterizedThreadStart. Der Parameter ist vom Typ object und muss gecastet werden.
http://msdn.microsoft.com/en-us/library/system.threading.parameterizedthreadstart(v=vs.110).aspx
Der Weg von hustbaer mit den Lambda-Ausdrücken ist aber der schönere.werkla4 schrieb:
Noch eine frage: Wenn mehrere threads zeitgleich laufen und auf der festplatte etwas abspeichern wollen, da gibt es hoffentlich keine komplikationen (bei evtl. überlappung), das abspeichern wird bestimmt einen nach den anderen erledigt...?
Kein Problem. Du schreibst ja in verschiedene Dateien.
-
werkla4 schrieb:
// ################################################################################################# /* Ziel: Es sollen mehrere berechnungen "zeitgleich" ausgeführt werden um zeit zu sparen * (natürlich könnte ich das auch nacheinander abarbeiten lassen aber da ich datenmengen jenseits * von gut und böse berechnen möchte, wollte ich auch meinen computer ganz ausschöpfen! Momentan * läuft dieser nur mit 20-30% CPU-Auslastung) * * 1. Frage: Wann kommt das programm hier an: Wenn alle drei threads zuende gelaufen sind?? * Bzw. Wie programmiere ich das, damit er erst hier weitermacht nachdem alle drei threads zuende * sind!! (damit keine überlappungen von berechnungen passieren) * * 2. Frage: Ich habe einen quadcore PC, darf ich dann nur maximal 4 threads öffnen? * Bzw. Würden sich die threads bestenfall so gut aufteilen, das ein thread den ersten CPU-Kern * benutzt, der zweite den zweiten CPU-Kern... * Oder habe ich da einen denkfehler? * * P.s. Ich bin absoluter programmieranfänger, also bitte ich um nachsicht für meine fragen. */
Ziel:
Ok. Da Du aber Daten auf der HD speicherst, könnte das der Flaschenhals sein. Der Thread langweilt sich bei Zugriffen auf die Festplatte.1. Frage:
Das Programm käme an sobald die Threads gestartet wurden. Die Lösung (join) wurde ja schon genannt.2. Frage:
Nein beliebig viele. Auch auf Singlecore CPUs kann man Multithreading betreiben und ist für manche Anwendungen auch notwendig (z.B. ein Consolenbasierter Chat. Ein Thread wartet auf Benutzereingaben, ein anderer zeigt die Texte der Chatpartner). Um die Verteilung von Prozessen und Threads auf die einzelnen Kerne kümmert sich das OS. Man kann Einfluss nehmen indem man Thread/Prozess-Prioritäten setzt, aber das ist eher selten eine gute Idee.
Jetzt aber nicht den Fehlschluss ableiten, dass ein Programm schneller läuft, je mehr Threads man erstellt. Hast Du X Kerne und erstellst Y>X Threads, kommt es zwangsläufig zur wechselseitigen Ausführung. Dazu laufen im Hintergrund viele weitere Dienste und das OS selbst, die Kernzeit beanspruchen.Zu Deinem P.S.
Als absoluter Anfänger direkt an Multithreading? Das ist mutigNachtrag: Lies Dir das hier durch http://www.albahari.com/threading/
Du hast wie es aussieht eine bestimmte Aufgabe zu lösen die Threading-Techniken erfordern. In diesem Probekapitel findest Du alles notwendige dafür.
-
Ja, zu Frage (2) nochwas...
Du kannst grundsätzlich so viele Threads erzeugen wie du magst. Sobald du genug Threads beinander hast um immer alle Cores auszulasten ändert sich an der Geschwindigkeit dabei kaum mehr was.Zwei Dinge die du aber evtl. bedenken solltest:
-
Je mehr Threads du erzeugst, umso langsamer werden ggf. andere Programme. Das ist natürlich abhängig vom Scheduler des OS, aber wenn du "nett" sein willst solltest du nicht hunderte Threads erzeugen die alle permanent Vollgas geben. Zumindest nicht bei Desktop Anwendungen. Wenn deine Anwendung die einzig relevante auf dem ganzen System ist, ist es ziemlich egal.
-
Wenn du aus mehreren Threads gleichzeitig grössere Datenmengen liest oder schreibst, dann bremst das eher als es hilft. Weil sich - vereinfacht gesagt - die Festplatte leichter tut wenn sie Files schön eines nach dem anderen schreiben kann, als wenn sie dauernd zwischen mehreren Files hin-und-her wechseln muss. (Das selbe trifft auch zu wenn man mit nur einem Thread abwechselnd kleine Stücke in unterschiedlichen Files liest oder schreibt, bzw. sogar wenn es das selbe File ist man aber dauernd in diesem File hin und herspringt.)
Bei SSDs gilt prinzipiell das selbe, nur ist der Effekt dort wesentlich weniger ausgeprägt.
-
-
Ich danke euch für die gute auskunft. Ich denke soweit ist alles klar was dieses thema angeht, da muss ich doch glatt meine vorüberlegung zu meinem programm mit dem neuen wissen abgleichen
-
werkla4 schrieb:
Ich denke soweit ist alles klar was dieses thema angeht
An dieser Stelle kann ich dir garantieren: Nein!
-
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?
-
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?