Autor |
Beitrag |
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Sa 24.04.10 20:31
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?
_________________ Die Lösung ist nicht siebzehn.
|
|
Christian S.
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Sa 24.04.10 21: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 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.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Sa 24.04.10 21: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 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?
_________________ Die Lösung ist nicht siebzehn.
|
|
Christian S.
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Sa 24.04.10 21: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 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.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Sa 24.04.10 21: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
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 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?
_________________ Die Lösung ist nicht siebzehn.
|
|
Christian S.
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Sa 24.04.10 21: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
Versuch mal, den Aufruf der MessageBoxes in Invoke zu verpacken.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Sa 24.04.10 22:05
Okay, muss nur grad mein Wissen über delegates auffrischen
_________________ Die Lösung ist nicht siebzehn.
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Sa 24.04.10 22:14
Stimmt das so?
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!
_________________ Die Lösung ist nicht siebzehn.
|
|
Christian S.
Beiträge: 20451
Erhaltene Danke: 2264
Win 10
C# (VS 2019)
|
Verfasst: Sa 24.04.10 22:17
Was soll das für eine Syntax sein?
Hier wird die Syntax für anonyme Methoden und Delegaten gezeigt: prismwiki.codegear.c...ethods_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.
_________________ Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Mo 26.04.10 17: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 |
_________________ Die Lösung ist nicht siebzehn.
|
|
Kha
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mo 26.04.10 18: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 .
_________________ >λ=
|
|
Mitmischer 1703
Beiträge: 754
Erhaltene Danke: 19
Win 7, Debian
Delphi Prism, Delphi 7, RAD Studio 2009 Academic, C#, C++, Java, HTML, PHP
|
Verfasst: Mo 26.04.10 18: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
Einloggen, um Attachments anzusehen!
_________________ Die Lösung ist nicht siebzehn.
|
|
Kha
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 27.04.10 00:46
Soo, noch einmal ein wenig darüber nachgedacht und zu dem Schluss gekommen: Das funktioniert ganz berechtigt bei dir nicht .
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 .
_________________ >λ=
|
|
|