Entwickler-Ecke
Andere .NET-Sprachen - parallel loop Sync
Mitmischer 1703 - Sa 24.04.10 21:31
Titel: parallel loop Sync
Hi DF!
Ich muss euch wegen der parallel loop-Funktion noch mal ansprechen.
Vielleicht ist der Titel nicht ganz korrekt, aber bei folgender Prozedur:
Delphi-Prism-Quelltext
1: 2: 3: 4: 5:
| method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); begin for parallel i: Int32 := 0 to 3 do begin MessageBox.Show(i.ToString); end; |
`
Muss ich die Messageboxen in der Reihenfolge 3,2,1,0 wegklicken, ansonsten werden mir lustigste Exceptions geworfen. Warum ist das so? Was genau passiert in dem parallel Block?
Christian S. - Sa 24.04.10 22:02
Wenn ich nur Deinen Code benutze, bekomme ich keine Exceptions, egal in welcher Reihenfolge ich die Dinger wegklicke.
Zur Schleife ist zuerst einmal der
Beitrag im Wiki [
http://prismwiki.codegear.com/en/Parallel_Loops] ganz hilfreich. Wichtig sind wohl noch folgende Punkte: Der Code wird
nicht im GUI-Thread ausgeführt, Zugriffe auf die GUI müssen daher in Aufrufe von
Invoke verpackt werden. Außerdem: Die Reihenfolge, in der die Iterationen ausgeführt werden bzw. fertig werden, ist unbekannt.
Mitmischer 1703 - Sa 24.04.10 22:08
Christian S. hat folgendes geschrieben : |
Wenn ich nur Deinen Code benutze, bekomme ich keine Exceptions, egal in welcher Reihenfolge ich die Dinger wegklicke. |
Hmm, das ist natürlich doof...
Wie bekomm ich denn mein VS upgegradet?
Christian S. hat folgendes geschrieben : |
Zur Schleife ist zuerst einmal der Beitrag im Wiki [http://prismwiki.codegear.com/en/Parallel_Loops] ganz hilfreich. Wichtig sind wohl noch folgende Punkte: Der Code wird nicht im GUI-Thread ausgeführt, Zugriffe auf die GUI müssen daher in Aufrufe von Invoke verpackt werden. Außerdem: Die Reihenfolge, in der die Iterationen ausgeführt werden bzw. fertig werden, ist unbekannt. |
Welches Objekt hat denn diese Methode?
Christian S. - Sa 24.04.10 22:13
Mitmischer 1703 hat folgendes geschrieben : |
Christian S. hat folgendes geschrieben : | Wenn ich nur Deinen Code benutze, bekomme ich keine Exceptions, egal in welcher Reihenfolge ich die Dinger wegklicke. |
Hmm, das ist natürlich doof... |
Ist das denn wirklich Dein Code? Denn in dem Quelltext, den Du hier gepostet hast, steht ein "begin" zu viel drin, was drauf hindeutet, dass Du da irgendwas entfernt hast.
Ansonsten: Welche Exceptions kommen denn?
Mitmischer 1703 hat folgendes geschrieben : |
Wie bekomm ich denn mein VS upgegradet? |
Ich glaube nicht, dass das mit Deinem VS oder mit der Prism-Version zusammenhängt. Genauer kann man das aber erst bei Kenntnis der Exception sagen.
Mitmischer 1703 hat folgendes geschrieben : |
Christian S. hat folgendes geschrieben : | Zur Schleife ist zuerst einmal der Beitrag im Wiki [http://prismwiki.codegear.com/en/Parallel_Loops] ganz hilfreich. Wichtig sind wohl noch folgende Punkte: Der Code wird nicht im GUI-Thread ausgeführt, Zugriffe auf die GUI müssen daher in Aufrufe von Invoke verpackt werden. Außerdem: Die Reihenfolge, in der die Iterationen ausgeführt werden bzw. fertig werden, ist unbekannt. |
Welches Objekt hat denn diese Methode? |
Alles, was von Control abgeleitet ist, IIRC. Normalerweise nimmt man die
Invoke-Methode der Form.
Mitmischer 1703 - Sa 24.04.10 22:22
Christian S. hat folgendes geschrieben : |
Mitmischer 1703 hat folgendes geschrieben : | Christian S. hat folgendes geschrieben : | Wenn ich nur Deinen Code benutze, bekomme ich keine Exceptions, egal in welcher Reihenfolge ich die Dinger wegklicke. |
Hmm, das ist natürlich doof... |
Ist das denn wirklich Dein Code? Denn in dem Quelltext, den Du hier gepostet hast, steht ein "begin" zu viel drin, was drauf hindeutet, dass Du da irgendwas entfernt hast. |
Stimmt, ich hab die letzten beiden ends weggelassen :oops:
Christian S. hat folgendes geschrieben : |
Ansonsten: Welche Exceptions kommen denn? |
Ich zähle auf (Exception, Klickreihenfolge): InvalidOperationException (2,0), NotSupportedException (2,1), da steht dann als Fehlerbeschreibung "SignalAndWait in einem STA-Thread wird nicht unterstützt", AggregateException(1,3,0) und einmal kommt Windows 7 mit "...exe funktioniert nicht mehr..."
Christian S. hat folgendes geschrieben : |
Mitmischer 1703 hat folgendes geschrieben : | Wie bekomm ich denn mein VS upgegradet? |
Ich glaube nicht, dass das mit Deinem VS oder mit der Prism-Version zusammenhängt. Genauer kann man das aber erst bei Kenntnis der Exception sagen.
Mitmischer 1703 hat folgendes geschrieben : | Christian S. hat folgendes geschrieben : | Zur Schleife ist zuerst einmal der Beitrag im Wiki [http://prismwiki.codegear.com/en/Parallel_Loops] ganz hilfreich. Wichtig sind wohl noch folgende Punkte: Der Code wird nicht im GUI-Thread ausgeführt, Zugriffe auf die GUI müssen daher in Aufrufe von Invoke verpackt werden. Außerdem: Die Reihenfolge, in der die Iterationen ausgeführt werden bzw. fertig werden, ist unbekannt. |
Welches Objekt hat denn diese Methode? | Alles, was von Control abgeleitet ist, IIRC. Normalerweise nimmt man die Invoke-Methode der Form. |
Ist das Invoke wie das Syncronize in Delphi?
Christian S. - Sa 24.04.10 22:52
Invoke führt den übergebenen Code im Thread des Controls auf, über das Invoke aufgerufen wird (also meistens die Form, entsprechend also der GUI-Thread). Wenn Synchronize sowas macht, dann ist es dasselbe. Das ist bei mir einfach zu lang her mit Delphi :D
Versuch mal, den Aufruf der MessageBoxes in Invoke zu verpacken.
Mitmischer 1703 - Sa 24.04.10 23:05
Okay, muss nur grad mein Wissen über delegates auffrischen :les:
Mitmischer 1703 - Sa 24.04.10 23:14
Stimmt das so?
Delphi-Prism-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:
| StringDelegate = public delegate (input : String); MainForm = partial class(System.Windows.Forms.Form) private method MainForm_Load(sender: System.Object; e: System.EventArgs); method button1_Click(sender: System.Object; e: System.EventArgs); protected method Dispose(disposing: Boolean); override; public constructor; end;
implementation
{$REGION Construction and Disposition} constructor MainForm; begin InitializeComponent();
end;
method MainForm.Dispose(disposing: Boolean); begin if disposing then begin if assigned(components) then components.Dispose();
end; inherited Dispose(disposing); end; {$ENDREGION}
method MainForm.MainForm_Load(sender: System.Object; e: System.EventArgs); begin end;
method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); begin for parallel i: Int32 := 0 to 3 do begin Invoke(new StringDelegate(MessageBox.Show(i.ToString))); end; end;
end. |
Er will das aber nicht nehmen und wirft mir Variable erforderlich und unsafe benötigt
Kannst ja mal drüberschauen, ich glaub ich bin jetzt zu müde ;)
Bis Morgen!
Christian S. - Sa 24.04.10 23:17
Was soll das für eine Syntax sein? :gruebel:
Hier wird die Syntax für anonyme Methoden und Delegaten gezeigt:
http://prismwiki.codegear.com/en/Anonymous_Methods_and_Delegates
Lass Dich von dem Dispatcher-Kram beim Invoke nicht irritieren, das ist für WPF und muss Dich nicht interessieren. Die Syntax für anonomye Methoden / Delegaten ist für Dich wichtig.
Mitmischer 1703 - Mo 26.04.10 18:22
ich habe jetzt folgendes:
Delphi-Prism-Quelltext
1: 2: 3: 4: 5: 6:
| method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); begin for parallel i: Int32 := 0 to 0 do begin Invoke(method (nr : Integer); begin MessageBox.Show(nr.ToString) end, I); end; end; |
Ich habs mal gedebuggt und er läuft theoretisch auch schön alles durch, alles wunderbar - nur werden die MessageBoxen nicht angezeigt und mein Programm friert ein. Funktioniert der Code bei dir?
Edit:
Das hier geht auch nicht:
Delphi-Prism-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| method MainForm.button1_Click(sender: System.Object; e: System.EventArgs); begin for parallel i: Int32 := 0 to 0 do begin Invoke(new StringDelegate(@DisplayString)); end; end;
method MainForm.DisplayString(input : String); begin MessageBox.Show(input); end |
Kha - Mo 26.04.10 19:12
Irgendetwas scheint mit deinen MessageBoxen ganz und gar nicht zu stimmen ;) . Kannst du die erzeugte Exe mal anhängen? So langsam würde ich mir das gerne mal selbst anschauen :gruebel: .
Mitmischer 1703 - Mo 26.04.10 19:31
jap
Oder braucht das Invoke irgendne Klasse? Komischerwiese gibt es Self.Invoke, aber MainForm.Invoke nicht. Hat das was zu bedeuten?
Naja, wie dem auch sei, im Anhang liegt die Exe :D
Kha - Di 27.04.10 01:46
Soo, noch einmal ein wenig darüber nachgedacht und zu dem Schluss gekommen: Das funktioniert ganz berechtigt bei dir nicht :think: .
Gehen wir das Drama mal durch:
Der GUI-Thread ruft
Parallel.For auf, welches ThreadPool-Threads anfordert und wartet, bis alle beendigt sind. Die Neben-Threads rufen nun
Invoke auf, was eine Window Message an den Hauptthread schickt mit der Bitte um Bearbeitung des Delegates und auf das Ergebnis wartet. Dummerweise kann der Haupt-Thread schlecht seine Nachrichtenschleife abarbeiten, da er ja selbst auf das Ende von
Parallel.For wartet -> klassischer Deadlock :) .
Bei mir ist das Problem interessanterweise dadurch nicht aufgetreten, dass
Parallel (sinnvollerweise) den Task des ersten Schleifendurchlaufs "inline", in diesem Fall also im GUI-Thread, ausführt -
Invoke entfällt. Das scheint bei deiner PFX-Version noch nicht der Fall gewesen zu sein.
Das Lösen des Deadlocks ist in diesem Fall recht einfach, denn eigentlich gibt es keinen Grund, dass hier irgendjemand wartet. Den Haupt-Thread interessiert es nicht, wann die Schleife beendet ist, also könntest du sie durch ein
Task.Factory.StartNew selbst in einem Workerthread starten, oder du benutzt statt
Invoke BeginInvoke, damit die Iterationen gar nicht erst auf die GUI warten.
Je nachdem, wie dein eigentliches Problem aussieht, gibt es sicher auch noch andere Lösungen. Wenn du zum Beispiel gar nicht die Features von
Parallel.For wie Rückgabewert, Break/Exit, ... benötigst, gibt es keinen Grund, dafür einen weiteren Worker-Thread in Anspruch zu nehmen. Und wenn du statt
BeginInvoke Task.ContinueWith benutzt, musst du dich auch nicht mehr ums Weitergeben der Exceptions kümmern.
C#-Quelltext
1: 2: 3: 4:
| for (int i = 0; i++; i < 10) Task.Factory.StartNew(() => { return DoSomethingExpensive(); }).ContinueWith(ShowInGui, TaskScheduler.FromCurrentSynchronizationContext()); |
PS: Wenn du nicht auf eine neuere Prism-Version upgraden kannst, lass doch wenigstens
for parallel links liegen und benutze dafür die PFX-Version aus Rx durch direkte Aufrufe. Wie du siehst, kann eine gewöhnliche For-Schleife manchmal sogar effizienter sein ;) .
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 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!