In Visual Basic worden asynchrone aanroepen en evenementverwerking vaak op verschillende manieren geïmplementeerd, afhankelijk van de versie van de taal en het type applicatie. In klassieke WinForms-applicaties in VB.NET wordt de verwerking van de gebeurtenisqueue (event queue) meestal gedaan met de aanroep Application.DoEvents(). Deze methode stelt de gebeurtenisverwerker in staat om "de controle los te laten", zodat andere berichten kunnen worden verwerkt zonder de hoofdthread te blokkeren:
While loading Application.DoEvents() 'Maakt UI mogelijk om te reageren op gebruikersacties End While
Voor asynchrone uitvoering van taken in .NET met VB.NET worden de volgende methoden gebruikt:
BackgroundWorker — een WinForms-component voor het verplaatsen van langdurige operaties naar een aparte thread met veilige interactie met de UI-thread.Async/Await — een handige moderne asynchroniciteitssysteem, dat in .NET 4.5 verscheen, stelt je in staat om asynchrone code "zoals synchrone" te schrijven:Public Async Function LoadDataAsync() As Task Dim result As String = Await GetWebDataAsync() TextBox1.Text = result End Function
Verschillen:
DoEvents verwerkt eenvoudig de UI-berichtenqueue en creëert geen nieuwe threads.BackgroundWorker verplaatst het werk naar een aparte thread, met een gebeurtenis voor veilige terugkeer naar de UI-thread.Async/Await implementeert asynchroniciteit, terwijl het de controle van de UI-thread encapsuleert.Wat is het gevaar van het gebruik van
DoEventsin een lus, als je een bestand van de schijf wilt laden en de ProgressBar wilt bijwerken?
Antwoord:
DoEvents geeft tijdelijk de controle aan andere Windows-gebeurtenissen, maar bevrijdt de thread niet. Het gebruik ervan in zware lussen (bijvoorbeeld het lezen van een groot bestand met gelijktijdige interface-updates) kan leiden tot onverwachte bugs: gebruikersgebeurtenissen en muisgebeurtenissen worden verwerkt, wat kan leiden tot het opnieuw starten van de verwerking of zelfs "bevriezen" van de applicatie. Als er een zware lading wordt verwacht, dient BackgroundWorker of Task te worden gebruikt.
Voorbeeld van een verkeerde aanpak:
For i = 1 To 1000000 ProgressBar1.Value = i / 10000 Application.DoEvents() 'Bevrijdt de hoofdthread niet! Next
Geschiedenis
DoEvents gebruikt binnen een langdurige lusr voor het bijwerken van de voortgangsindicator. Hierdoor "bevroor" de interface: als de gebruiker opnieuw op de knop "Openen" klikte, begon er een tweede bestandleesproces, mengde met de eerste, wat leidde tot gegevensvervorming en een crash van de applicatie.Geschiedenis
DoEvents in een lus, omdat hij niet bekend was met BackgroundWorker. Bij het bijwerken van een enorme hoeveelheid punten begon de applicatie vast te lopen en "verliet" uiteindelijk wegens een overflow van de Windows-berichtenqueue.Geschiedenis
Er werd een asynchrone aanroep gedaan via Async/Await, zonder te begrijpen dat langdurige taken niet in de "hete" UI-thread zonder Await Task.Run(...) moeten worden uitgevoerd. Resultaat: de interface reageerde niet op klikken en de voortgangsbalk werd niet bijgewerkt, omdat de langdurige methode toch op de hoofdthread werd uitgevoerd.