In Visual Basic werden asynchrone Aufrufe und die Verarbeitung von Ereignissen normalerweise auf unterschiedliche Weise implementiert, abhängig von der Version der Sprache und dem Typ der Anwendung. In klassischen WinForms-Anwendungen wird die Ereigniswarteschlange (Event Queue) in VB.NET normalerweise durch den Aufruf von Application.DoEvents() verarbeitet. Diese Methode ermöglicht es dem Ereignisbehandler, die Kontrolle "freizugeben", damit andere Nachrichten verarbeitet werden können, ohne den Hauptthread zu blockieren:
While loading Application.DoEvents() 'Ermöglicht es der UI, auf Benutzeraktionen zu reagieren End While
Für die asynchrone Ausführung von Aufgaben in .NET mit VB.NET werden verwendet:
BackgroundWorker — eine WinForms-Komponente zur Auslagerung langwieriger Operationen in einen separaten Thread mit sicherer Interaktion mit dem UI-Thread.Async/Await — ein modernes, benutzerfreundliches System der Asynchronität, das mit .NET 4.5 eingeführt wurde, ermöglicht das Schreiben von asynchronem Code "wie synchronen":Public Async Function LoadDataAsync() As Task Dim result As String = Await GetWebDataAsync() TextBox1.Text = result End Function
Unterschiede:
DoEvents verarbeitet einfach die Warteschlange der UI-Nachrichten und erstellt keine neuen Threads.BackgroundWorker führt die Arbeit in einem separaten Thread aus, mit einem Ereignis für einen sicheren Rückkehr in den UI-Thread.Async/Await implementiert Asynchronität und kapselt die Rückkehr der Kontrolle in den UI-Thread.Was ist die Gefahr bei der Verwendung von
DoEventsin einer Schleife, wenn es darum geht, eine Datei von der Festplatte zu laden und den ProgressBar zu aktualisieren?
Antwort:
DoEvents überträgt vorübergehend die Kontrolle an andere Windows-Ereignisse, befreit jedoch nicht den Thread. Wenn es in schweren Schleifen (z.B. beim Lesen einer großen Datei und gleichzeitigen Aktualisieren der Benutzeroberfläche) verwendet wird, können unerwartete Bugs auftreten: Benutzer- und Mausklickereignisse werden verarbeitet, was zu einer erneuten Auslösung der Verarbeitung oder sogar zum "Einfrieren" der Anwendung führen kann. Bei einer schweren Belastung sollte BackgroundWorker oder Task verwendet werden.
Beispiel eines falschen Ansatzes:
For i = 1 To 1000000 ProgressBar1.Value = i / 10000 Application.DoEvents() 'Befreit nicht den Hauptthread! Next
Geschichte
DoEvents verwendet, um den Fortschrittsindikator innerhalb einer langen Schleife zum Lesen einer Datei zu aktualisieren. Infolgedessen "hängte" die Benutzeroberfläche: wenn der Benutzer erneut auf die Schaltfläche "Öffnen" klickte, begann ein zweiter Leseprozess der Datei, vermischt mit dem ersten, was zu Datenverzerrungen und einem Absturz der Anwendung führte.Geschichte
DoEvents in einer Schleife zu aktualisieren, da er mit BackgroundWorker nicht vertraut war. Bei der Aktualisierung einer riesigen Menge von Punkten begann die Anwendung zu "stocken" und stürzte schließlich aufgrund von Überlastung der Windows-Nachrichtenschlange ab.Geschichte
Es wurde ein asynchroner Aufruf über Async/Await verwendet, ohne zu verstehen, dass langwierige Arbeiten nicht im "heißen" UI-Thread ohne Await Task.Run(...) gestartet werden können. Ergebnis: die Benutzeroberfläche reagierte nicht auf Klicks, und der ProgressBar wurde nicht aktualisiert, da die langwierige Methode immer noch im Hauptthread ausgeführt wurde.