Entwickler-Ecke
Basistechnologien - Programmablauf "warten" lassen
VampireSilence - So 17.10.10 12:37
Titel: Programmablauf "warten" lassen
Teilweise habe ich das Problem, dass ich mein Programm warten lassen muss, um diverse asynchrone Funktionen zu "synchronisieren", zB wenn ich Daten aus dem Internet lade oder Ähnliches. Jetzt habe ich mir bisher immer mit der folgenden Prozedure geholfen:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10:
| DateTime wait = DateTime.Now.AddSeconds(30);
while (DateTime.Now.Subtract(wait).TotalSeconds < 0) { Application.DoEvents(); }
|
Das Programm wartet zwar jetzt 30 Sekunden und es blockiert auch nicht, da ich ja jedes Mal
Application.DoEvents() ausführe, aber es verbraucht in diese Moment 100% CPU und das stört mich. Mir war eigtl von vornherin klar, dass es nur eine Notlösung war und jetzt, wo sich der CPU-Verbrauch zu einem Problem entwicklet, wollte ich mal fragen: wie macht man sowas richtig ?
mfg
- VampireSilence
jaenicke - So 17.10.10 12:46
Du kannst das in Threads auslagern und dir von diesem (oder aus deinen asynchronen Fubnktionen) Bescheid sagen lassen, wenn die Bearbeitung abgeschlossen ist. So musst du nicht warten, sondern hast ein Event innerhalb dessen du dann weitermachen kannst. ;-)
Kha - So 17.10.10 14:07
jaenicke hat folgendes geschrieben : |
| oder aus deinen asynchronen Fubnktionen |
Eben. Wenn man schon einen asynchronen Vorgang zur Verfügung hat, muss es auch einen Weg ohne zusätzliche Threads oder Synchronisierung geben.
VampireSilence - So 17.10.10 15:25
Ja, richtig. Bei "some code" steht noch einiges und da bestimmte Funktionen keine synchronen Varianten besitzen, ist das Auslagern keine gute Alternative. Damit wäre dann im Prinzip nichts gewonnen.
Teilweise füttere ich die while()-Condition auch nicht mit einer Zeitangaben, sondern einfach mit einer variablen, die vom asynchronen Prozess zu liefern ist, aber das macht für die CPU ja erstmal keinen Unterschied.
Das einzige, das ich noch kennen würde, wäre dann Thread.Sleep(), aber damit blockiert die Anwendung, was auch nicht gut wäre.
mfg
- VampireSilence
jaenicke - So 17.10.10 15:27
VampireSilence hat folgendes geschrieben : |
| sondern einfach mit einer variablen, die vom asynchronen Prozess zu liefern ist |
Und genau an der Stelle kannst du auch ein Event auslösen oder Ähnliches. Damit sagst du also Bescheid, dass du fertig bist und reagierst dann darauf.
Wenn du das ganze ereignisorientiert umsetzt, entstehen solche Warteszenarien gar nicht erst.
VampireSilence - So 17.10.10 15:46
Ich glaube wir reden grade aneinander vorbei, also schreibe ich jetzt einfach mal das auf, wie ich dich verstehe. Also:
C#-Quelltext
1: 2: 3: 4:
| while (!AsynchronerProzessHatVariableÜbergeben) { Application.DoEvents(); } |
Und damit wären wir ja wieder bei 100% CPU, also wäre nichts gewonnen.
mfg
- VampireSilence
jaenicke - So 17.10.10 15:53
Nein, ganz ohne Schleife.
Mal Pseudocode (aus dem Kopf kann ich das in C# anders als in Delphi leider nicht in echtem Code :oops:):
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| Buttonclick: { BereiteBerechnungVor(); StarteAsynchroneBerechnung(); }
Asynchron: { Berechne(); InvokeEventAnHauptThread(); }
HauptThreadEvent: { ÜbernehmeDaten(); Messagedialog.Show("Fertig"); } |
VampireSilence - So 17.10.10 19:14
@jaenicke
Ok, ich glaube zumindest weiss ich jetzt, wo unsere Differenz ist^^
In Zeile 16 Spuckt dein Ergebnis "Fertig" aus und ist damit beendet. Bei mir ist das aber nicht der Fall. Bei mir sieht es schematisch eher so aus:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| anyFunction() { result ErgebnisA = AsynchroneFunktion(Parameter); andereFunktion(ErgebnisA); } |
Oder kurz gesagt: meine asynchrone Funktion ist nicht das Ende. Danach geht es noch weiter. Und dieser weitere Code benötigt das Ergebnis der Funktion bereits und kann ohne diese nicht fortfahren. Er müsste also bei "Code B" pausieren und nach der Berechnung der AF (ich kürz das ma ab..) an der selben Stelle wieder fortfahren.
mfg
- VampireSilence
jaenicke - So 17.10.10 19:27
Genau so meine ich das ja. Wenn du vom asynchronen Aufruf oder Thread die Benachrichtigung mit dem Ergebnis bekommen hast, dann machst du darin weiter. Und rufst ggf. die nächste asynchrone Funktion auf.
Ereignisbasiert eben, genau wie Windows, .NET und C# insgesamt sind.
Du stellst dir das alles prozedural hintereinander vor. So wie es früher bei DOS war, immer eins nach dem anderen. So funktioniert das aber nicht gut, wie du ja selbst schon gemerkt hast...
// EDIT:
Ansonsten gibt es auch noch die Möglichkeit mit WaitForMultipleObjects zu warten um statt reinem Polling auch bei Nachrichten zu reagieren, damit die Anwendung noch reagiert.
Das ist aber die schlechtere Lösung...
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 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!