Entwickler-Ecke
WinForms - Threads parallelisieren (for-Schleife)
sentropie - Fr 08.10.10 12:57
Titel: Threads parallelisieren (for-Schleife)
Hallo,
ich lerne momentan C# und versuche mich an einem WindowsForms-Programm, in welchem ich mit Threads herumspiele. Im Prinzip besteht das Fenster aus einem Button und zwei Textboxen. Beim Klick auf den Button soll in beiden Textboxen gleichzeitig ein Zähler hochlaufen. Bei mir passiert das jedoch schön nacheinander - auch wenn es zufällig erscheint, in welcher Box begonnen wird.
Hier kommt der Code. Ich freue mich auf Ratschläge.
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64:
| using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading;
namespace Forms_Threading { public partial class Form1 : Form { public Form1() { InitializeComponent(); }
private int max = 10000;
private void fkt1() { MethodInvoker m1 = delegate { for (int j = 0; j <= max; j++) { textBox1.Text = j.ToString(); textBox1.Refresh(); } };
Invoke(m1); }
private void fkt2() { MethodInvoker m2 = delegate { for (int i = 0; i <= max; i++) { textBox2.Text = i.ToString(); textBox2.Refresh(); } };
Invoke(m2); }
private void button1_Click(object sender, EventArgs e) { textBox1.Text = ""; textBox2.Text = "";
Thread t1 = new Thread(fkt1); Thread t2 = new Thread(fkt2); t1.IsBackground = true; t2.IsBackground = true; t1.Start(); t2.Start(); } } } |
Th69 - Fr 08.10.10 13:47
Du "invoke"st ja auch jeweils die ganze Schleife.
Du mußt nur den GUI-Teil (d.h. die TextBox-Methoden) per Invoke aufrufen.
Falls du schon mit VS 2010 und .NET 4.0 arbeitest, kannst du dir mal die "Task Parallel Library" (TPL) anschauen, s.a.
http://www.c-sharp-forum.de/viewtopic.php?p=604486#604486
danielf - Fr 08.10.10 14:00
Und selbst dann laufen die Threads nicht gleichzeitig. Rechenzeit gibts nur einmal :) So dass mal thread1 und dann wieder thread2 dran ist.
Mit dem BackgroundWorker kannst du es ein bisschen (ressourcemässig) schlanker gestalten. Darüber hinaus beenden sich die BackgroundWorker wenn sich der Hauptthread beendet.
Besser wäre auch, wenn du nicht fkt1 und fkt2 machst, sondern das zu ändernde TextBox-Control der funktion mitgibst (z.B.
hier [
http://dotnet-snippets.de/dns/methode-mit-parameter-in-eigenem-thread-starten-SID583.aspx]).
Gruß
Implementation - Fr 08.10.10 14:26
danielf hat folgendes geschrieben : |
Und selbst dann laufen die Threads nicht gleichzeitig. Rechenzeit gibts nur einmal :) So dass mal thread1 und dann wieder thread2 dran ist. |
Und was ist wenn man mehrere CPU's hat?
Oder eine CPU mit mehreren Kernen?
Dann läuft's gleichzeitig :wink:
danielf - Fr 08.10.10 14:28
Nein ;p
Weil es immer noch der gleiche Prozess ist .. und dieser läuft immer nur auf einem CPU.
Dann brauchst du schon Parallel Framework ;p
Kha - Fr 08.10.10 15:29
danielf hat folgendes geschrieben : |
Weil es immer noch der gleiche Prozess ist .. und dieser läuft immer nur auf einem CPU. |
Äh, nein. Jeder Thread kann pro Time Slice auf jedem beliebigen Kern laufen, solange keine Affinity festgelegt ist.
danielf hat folgendes geschrieben : |
Dann brauchst du schon Parallel Framework ;p |
Was natürlich auch nur einen Prozess benutzt und darin einen geschönten Threadpool ;) .
@
sentropie: :welcome: !
danielf - Fr 08.10.10 15:39
gefährliches Halbwissen ...
Da hab ich den Anlass doch gleich mal genutzt um MSDN (
Threads und Threading [
http://msdn.microsoft.com/de-de/library/6kac2kdh.aspx]) zu lesen.
Zitat: |
Dies ist bei Systemen mit mehreren Prozessoren auch tatsächlich der Fall, bei denen die ausführbaren Threads unter den verfügbaren Prozessoren aufgeteilt werden. |
Zitat: |
Ohne weitere Veränderungen würde dieselbe Anwendung auf einem Computer mit mehreren Prozessoren noch weitaus bessere Ergebnisse liefern. |
Na dann bin ich ja schon voll MultiCore unterwegs ;)
sentropie - Fr 08.10.10 18:21
Th69 hat folgendes geschrieben : |
Du "invoke"st ja auch jeweils die ganze Schleife.
Du mußt nur den GUI-Teil (d.h. die TextBox-Methoden) per Invoke aufrufen.
Falls du schon mit VS 2010 und .NET 4.0 arbeitest, kannst du dir mal die "Task Parallel Library" (TPL) anschauen, s.a. http://www.c-sharp-forum.de/viewtopic.php?p=604486#604486 |
Danke, nun klappt das schon mal.
Bei Gelegenheit werde ich mir mal die 4.0er Version anschauen. Aber wenn es auch "klassisch" geht, warum nicht? Daher habe ich erstmal so gemacht.
BackgroundWorker sollte ich mir in der Tat einmal genauer anschauen. Allerdings fand ich das auf den ersten Blick nicht so leicht verständlich. Aber mal gucken.
Alles in eine Funktion wäre eine weitere Verbesserungsmöglichkeit. Auch etwas für die nahe Zukunft. :)
@
Kha: Danke. :)
--------------------------------------
Jetzt, wo diese Sache läuft, möchte ich einen Schritt weitergehen. Ich habe einen Button und ein Textfeld hinzugefügt. Ich möchte nun, dass in dem Textfeld eine Zahl hochgezählt wird - und zwar bei jedem Klick +1. Ich bin jetzt so weit, dass die Klicks "registriert" werden, aber das Resultat sehe ich erst, nachdem die beiden Zähler-Threads fertig sind. (Also da steht z.B. eine 1, ich klick 3x und NACH dem Hochzählen erscheint eine 4. Das soll jedoch mehr oder weniger unmittelbar passieren.)
Das wäre der Button:
C#-Quelltext
1: 2: 3: 4: 5:
| private void button2_Click(object sender, EventArgs e) { int zahl = Convert.ToInt32(textBox3.Text) + 1; textBox3.Text = zahl.ToString(); } |
Ich habe da auch schon (erfolglos) probiert, mit einem weiteren Thread anzukommen, aber das veränderte alles entweder zum schlechteren oder änderte nichts. Ich habe da auch ein Verständnisproblem. Thread 1 und 2 (der Hauptthread sei 0) erzeuge ich ja in der Click-Methode des Button1. Der weiß natürlich nichts von einem Thread im 2. Button (und umgekehrt). In einer Konsolenanwendung würde ich die Threads "ja einfach" in der main-Funktion erzeugen, aber wie muss ich hier vorgehen? Wo erzeugt man da richtigerweise die Threads?
Kha - Fr 08.10.10 19:25
sentropie hat folgendes geschrieben : |
Ich bin jetzt so weit, dass die Klicks "registriert" werden [...] |
Wenn ich das bei mir ausprobiere, wird auch der Klick erst am Ende "visuell registriert". Und das liegt daran, dass dein Beispiel einfach noch nicht wirklich etwas mit Threads zu tun hat ;) . Da in den Nebenthreads nichts gearbeitet wird, nicht einmal ein
Thread.Sleep, sind sie die ganze Zeit am Invoken und du hast den gleichen Effekt, als ob du die Schleifen im GUI-Thread ausführen würdest - es werden keine Events abgearbeitet.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!