Delen via


Asynchroon programmeren met Async en Await (Visual Basic)

U kunt knelpunten in de prestaties voorkomen en de algehele reactiesnelheid van uw toepassing verbeteren met behulp van asynchrone programmering. Traditionele technieken voor het schrijven van asynchrone toepassingen kunnen echter ingewikkeld zijn, waardoor ze moeilijk kunnen worden geschreven, fouten kunnen worden opgespoord en onderhouden.

Visual Studio 2012 heeft een vereenvoudigde benadering, asynchrone programmering, geïntroduceerd die gebruikmaakt van asynchrone ondersteuning in .NET Framework 4.5 en hoger en in Windows Runtime. De compiler doet het moeilijke werk dat de ontwikkelaar heeft gebruikt en uw toepassing behoudt een logische structuur die lijkt op synchrone code. Als gevolg hiervan krijgt u alle voordelen van asynchrone programmering met een fractie van de inspanning.

Dit onderwerp bevat een overzicht van wanneer en hoe u asynchrone programmering gebruikt en koppelingen bevat naar ondersteuningsonderwerpen die details en voorbeelden bevatten.

Async verbetert de reactiesnelheid

Asynchroon is essentieel voor activiteiten die mogelijk worden geblokkeerd, bijvoorbeeld wanneer uw toepassing toegang heeft tot het web. De toegang tot een webresource is soms traag of vertraagd. Als een dergelijke activiteit wordt geblokkeerd binnen een synchroon proces, moet de hele toepassing wachten. In een asynchroon proces kan de toepassing doorgaan met ander werk dat niet afhankelijk is van de webresource totdat de potentieel blokkerende taak is voltooid.

In de volgende tabel ziet u typische gebieden waarin asynchrone programmering de reactiesnelheid verbetert. De vermelde API's van .NET Framework 4.5 en Windows Runtime bevatten methoden die ondersteuning bieden voor asynchrone programmering.

Toepassingsgebied Ondersteunende API's die asynchrone methoden bevatten
Webtoegang HttpClient, SyndicationClient
Werken met bestanden StorageFile,StreamWriter,StreamReader,XmlReader
Werken met afbeeldingen MediaCapture, , BitmapEncoderBitmapDecoder
WCF-programmering Synchrone en Asynchrone Bewerkingen

Asynchrony bewijst met name waardevol voor toepassingen die toegang hebben tot de UI-thread, omdat alle ui-gerelateerde activiteiten meestal één thread delen. Als een proces wordt geblokkeerd in een synchrone toepassing, worden alle processen geblokkeerd. Uw toepassing reageert niet meer en u kunt concluderen dat deze is mislukt wanneer de toepassing gewoon wacht.

Wanneer u asynchrone methoden gebruikt, blijft de toepassing reageren op de gebruikersinterface. U kunt bijvoorbeeld het formaat van een venster wijzigen of minimaliseren, of u kunt de toepassing sluiten als u niet wilt wachten totdat het is voltooid.

De asynchrone benadering voegt het equivalent van een automatische overdracht toe aan de lijst met opties waaruit u kunt kiezen bij het ontwerpen van asynchrone bewerkingen. Dat wil gezegd, u krijgt alle voordelen van traditionele asynchrone programmering, maar met veel minder inspanning van de ontwikkelaar.

Asynchrone methoden zijn gemakkelijker te schrijven

De trefwoorden Async en Await in Visual Basic vormen het hart van asynchrone programmering. Door deze twee trefwoorden te gebruiken, kunt u resources in .NET Framework of Windows Runtime gebruiken om bijna net zo eenvoudig een asynchrone methode te maken als u een synchrone methode maakt. Asynchrone methoden die u definieert met behulp Async van en Await worden asynchrone methoden genoemd.

In het volgende voorbeeld ziet u een asynchrone methode. Bijna alles in de code moet er volledig vertrouwd uitzien. In de opmerkingen worden de functies benoemd die u toevoegt om de asynchroniciteit te creëren.

U vindt een volledig WPF-voorbeeldbestand (Windows Presentation Foundation) aan het einde van dit onderwerp en u kunt het voorbeeld downloaden uit Async Sample: Voorbeeld van 'Asynchroon programmeren met Asynchroon programmeren met Async en Await'.

' Three things to note about writing an Async Function:
'  - The function has an Async modifier.
'  - Its return type is Task or Task(Of T). (See "Return Types" section.)
'  - As a matter of convention, its name ends in "Async".
Async Function AccessTheWebAsync() As Task(Of Integer)
    Using client As New HttpClient()
        ' Call and await separately.
        '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
        '  - getStringTask stores the task we get from the call to GetStringAsync.
        '  - Task(Of String) means it is a task which returns a String when it is done.
        Dim getStringTask As Task(Of String) =
            client.GetStringAsync("https://learn.microsoft.com/dotnet")
        ' You can do other work here that doesn't rely on the string from GetStringAsync.
        DoIndependentWork()
        ' The Await operator suspends AccessTheWebAsync.
        '  - AccessTheWebAsync does not continue until getStringTask is complete.
        '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
        '  - Control resumes here when getStringTask is complete.
        '  - The Await operator then retrieves the String result from getStringTask.
        Dim urlContents As String = Await getStringTask
        ' The Return statement specifies an Integer result.
        ' A method which awaits AccessTheWebAsync receives the Length value.
        Return urlContents.Length

    End Using

End Function

Als AccessTheWebAsync geen werk heeft dat het kan doen tussen het aanroepen van GetStringAsync en het wachten op de voltooiing ervan, kunt u uw code vereenvoudigen door deze in één enkele instructie aan te roepen en te wachten.

Dim urlContents As String = Await client.GetStringAsync()

De volgende kenmerken geven een overzicht van wat het vorige voorbeeld een asynchrone methode maakt:

  • De methodehandtekening bevat een Async modifier.

  • De naam van een asynchrone methode eindigt op conventie met een Async-achtervoegsel.

  • Het retourtype is een van de volgende typen:

    • Task(of TResult) als uw methode een retourinstructie heeft waarin de operand het type TResult heeft.
    • Task als uw methode geen retourinstructie heeft of een retourinstructie zonder operand heeft.
    • Sub als u een asynchrone gebeurtenis-handler schrijft.

    Zie 'Retourtypen en parameters' verderop in dit onderwerp voor meer informatie.

  • De methode bevat meestal ten minste één await-expressie, die een punt markeert waarop de methode niet kan worden voortgezet totdat de wachtende asynchrone bewerking is voltooid. Ondertussen wordt de methode gepauzeerd, en gaat de controle terug naar de aanroeper van de methode. In de volgende sectie van dit onderwerp ziet u wat er op het schorsingspunt gebeurt.

In asynchrone methoden gebruikt u de opgegeven trefwoorden en typen om aan te geven wat u wilt doen, en de compiler doet de rest, inclusief het bijhouden van wat er moet gebeuren wanneer het besturingselement terugkeert naar een wachtpunt in een onderbroken methode. Sommige routineprocessen, zoals lussen en afhandeling van uitzonderingen, kunnen moeilijk te verwerken zijn in traditionele asynchrone code. In een asynchrone methode schrijft u deze elementen net zoals in een synchrone oplossing en wordt het probleem opgelost.

Zie TPL en Traditional .NET Framework Asynchronous Programming voor meer informatie over asynchroon programmeren in eerdere versies van .NET Framework.

Wat gebeurt er in een Async-methode?

Het belangrijkste om te begrijpen in asynchrone programmering is hoe de controlestroom van methode naar methode wordt verplaatst. Het volgende diagram leidt u door het proces:

Diagram met het traceren van een asynchroon programma.

De getallen in het diagram komen overeen met de volgende stappen:

  1. Een gebeurtenishandler aanroept en wacht op de AccessTheWebAsync asynchrone methode.

  2. AccessTheWebAsync maakt een HttpClient exemplaar en roept de GetStringAsync asynchrone methode aan om de inhoud van een website als een tekenreeks te downloaden.

  3. Er gebeurt iets in GetStringAsync dat de voortgang ervan onderbreekt. Misschien moet er worden gewacht totdat een website is gedownload of een andere blokkeringsactiviteit. Om te voorkomen dat resources worden geblokkeerd, GetStringAsync levert dit de controle over de aanroeper AccessTheWebAsyncop.

    GetStringAsync retourneert een taak (van TResult) waarbij TResult een tekenreeks is en AccessTheWebAsync wijst de taak toe aan de getStringTask variabele. De taak vertegenwoordigt het doorlopende proces voor de aanroep naar GetStringAsync, met een toezegging om een werkelijke tekenreekswaarde te produceren wanneer het werk is voltooid.

  4. Omdat getStringTask nog niet is afgewacht, kan AccessTheWebAsync doorgaan met ander werk dat niet afhankelijk is van het uiteindelijke resultaat van GetStringAsync. Dat werk wordt vertegenwoordigd door een aanroep naar de synchrone methode DoIndependentWork.

  5. DoIndependentWork is een synchrone methode die het werk uitvoert en terugkeert naar de aanroeper.

  6. AccessTheWebAsync heeft geen werk meer om te doen zonder een resultaat van getStringTask. AccessTheWebAsync vervolgens wil de lengte van de gedownloade tekenreeks berekenen en retourneren, maar de methode kan die waarde pas berekenen als de methode de tekenreeks heeft.

    Daarom gebruikt AccessTheWebAsync een wachtoperator om zijn voortgang op te schorten en de controle over te dragen aan de methode die AccessTheWebAsync heeft aangeroepen. AccessTheWebAsync retourneert een Task(Of Integer) aan de aanroeper. De taak stelt een belofte voor om een geheel getal te produceren dat overeenkomt met de lengte van de gedownloade tekenreeks.

    Opmerking

    Als GetStringAsync (en daarom getStringTask) voltooid is voordat AccessTheWebAsync hierop wacht, blijft de controle in AccessTheWebAsync. De kosten van het opschorten en vervolgens terugkeren naar AccessTheWebAsync worden verspild als het aangeroepen asynchrone proces (getStringTask) al is voltooid, waardoor AccessTheWebSync niet hoeft te wachten op het uiteindelijke resultaat.

    In de aanroeper (de gebeurtenis-handler in dit voorbeeld) wordt het verwerkingspatroon voortgezet. De beller kan ander werk doen dat niet afhankelijk is van het resultaat van AccessTheWebAsync voordat hij dat resultaat wacht, of de beller kan onmiddellijk wachten. De gebeurtenishandler wacht op AccessTheWebAsync, en AccessTheWebAsync wacht op GetStringAsync.

  7. GetStringAsync voltooit en produceert een tekenreeksresultaat. Het resultaat van de tekenreeks wordt niet op de manier die u zou verwachten geretourneerd door de aanroep naar GetStringAsync. (Houd er rekening mee dat de methode al een taak heeft geretourneerd in stap 3.) In plaats daarvan wordt het tekenreeksresultaat opgeslagen in de taak die de voltooiing van de methode aangeeft. getStringTask De wachtoperator haalt het resultaat op van getStringTask. Met de toewijzingsinstructie wordt het opgehaalde resultaat toegewezen aan urlContents.

  8. Wanneer AccessTheWebAsync het tekenreeksresultaat is, kan de methode de lengte van de tekenreeks berekenen. Zodra het werk van AccessTheWebAsync voltooid is, kan de wachtende eventhandler hervatten. In het volledige voorbeeld aan het einde van het onderwerp kunt u bevestigen dat de gebeurtenis-handler de waarde van het lengteresultaat ophaalt en afdrukt.

Neem even de tijd om na te denken over het verschil tussen synchroon en asynchroon gedrag als u nieuw bent in asynchrone programmering. Een synchrone methode retourneert wanneer het werk is voltooid (stap 5), maar een asynchrone methode retourneert een taakwaarde wanneer het werk wordt onderbroken (stap 3 en 6). Wanneer de asynchrone methode uiteindelijk het werk voltooit, wordt de taak gemarkeerd als voltooid en wordt het resultaat, indien aanwezig, opgeslagen in de taak.

Zie Controlestroom in Async-programma's (Visual Basic) voor meer informatie over de controlestroom.

Asynchrone API-methoden

Mogelijk vraagt u zich af waar u methoden kunt vinden, zoals GetStringAsync die ondersteuning bieden voor asynchrone programmering. Het .NET Framework 4.5 of hoger bevat veel onderdelen waarmee Async en Await. U kunt deze leden herkennen door het achtervoegsel 'Async' dat is gekoppeld aan de naam van het lid en een retourtype van Task of Task(Of TResult). De System.IO.Stream klasse bevat bijvoorbeeld methoden zoals CopyToAsync, ReadAsyncen WriteAsync naast de synchrone methoden CopyTo, Readen Write.

De Windows Runtime bevat ook veel methoden die u kunt gebruiken met Async en Await in Windows-apps. Zie Asynchrone API's aanroepen in C# of Visual Basic, Asynchrone programmering (Windows Runtime-apps) en WhenAny: Bridging tussen .NET Framework en Windows Runtime voor meer informatie en voorbeeldmethoden.

Draden

Asynchrone methoden zijn bedoeld als niet-blokkerende bewerkingen. Een Await expressie in een asynchrone methode blokkeert de huidige thread niet terwijl de wachtende taak wordt uitgevoerd. In plaats daarvan registreert de expressie de rest van de methode als vervolg en retourneert het besturingselement naar de aanroeper van de asynchrone methode.

De Async trefwoorden en Await trefwoorden zorgen ervoor dat er geen extra threads worden gemaakt. Asynchrone methoden vereisen geen multithreading omdat een asynchrone methode niet wordt uitgevoerd op een eigen thread. De methode wordt uitgevoerd op de huidige synchronisatiecontext en gebruikt alleen tijd op de thread wanneer de methode actief is. U kunt Task.Run cpu-gebonden werk verplaatsen naar een achtergrondthread, maar een achtergrondthread helpt niet bij een proces dat alleen wacht tot er resultaten beschikbaar zijn.

De asynchrone benadering van programmeeractiviteiten is in bijna elk geval te verkiezen boven de bestaande benaderingen. Deze aanpak is met name beter dan BackgroundWorker voor I/O-gebonden bewerkingen, omdat de code eenvoudiger is en u niet hoeft te beschermen tegen racevoorwaarden. In combinatie met Task.Runasynchrone programmering is beter dan BackgroundWorker voor CPU-afhankelijke bewerkingen, omdat asynchrone programmering de coördinatiedetails van het uitvoeren van uw code scheidt van het werk dat Task.Run wordt overgedragen naar de threadpool.

Async en Await

Als u opgeeft dat een methode een asynchrone methode is met behulp van een Async-modifier , schakelt u de volgende twee mogelijkheden in.

  • De gemarkeerde asynchrone methode kan Await gebruiken om schorsingspunten aan te wijzen. De wachtoperator vertelt de compiler dat de asynchrone methode niet verder kan gaan dan dat punt totdat het wachtende asynchrone proces is voltooid. In de tussentijd keert de controle terug naar de aanroeper van de asynchrone methode.

    De schorsing van een asynchrone methode bij een Await expressie vormt geen exit van de methode en Finally blokken worden niet uitgevoerd.

  • De gemarkeerde asynchrone methode kan zelf worden afgewacht door methodes die deze aanroepen.

Een asynchrone methode bevat doorgaans een of meer exemplaren van een Await operator, maar het ontbreken van Await expressies veroorzaakt geen compilerfout. Als een asynchrone methode geen operator gebruikt Await om een veringspunt te markeren, wordt de methode uitgevoerd als een synchrone methode, ondanks de Async wijzigingsfunctie. De compiler geeft een waarschuwing voor dergelijke methoden uit.

Async en Await zijn contextuele trefwoorden. Zie de volgende onderwerpen voor meer informatie en voorbeelden:

Retourtypen en parameters

In .NET Framework-programmering retourneert een asynchrone methode meestal een Task of een taak (van TResult). Binnen een asynchrone methode wordt een Await operator toegepast op een taak die wordt geretourneerd vanuit een aanroep naar een andere asynchrone methode.

U geeft Taak(van TResult) op als het retourtype als de methode een Return-instructie bevat waarmee een operand van het type TResultwordt opgegeven.

U gebruikt Task als retourtype als de methode geen retourinstructie heeft of een retourinstructie heeft die geen operand retourneert.

In het volgende voorbeeld ziet u hoe u een methode kunt declareren en aanroepen die een Taak(TResult) retourneert of een Task:

' Signature specifies Task(Of Integer)
Async Function TaskOfTResult_MethodAsync() As Task(Of Integer)

    Dim hours As Integer
    ' . . .
    ' Return statement specifies an integer result.
    Return hours
End Function

' Calls to TaskOfTResult_MethodAsync
Dim returnedTaskTResult As Task(Of Integer) = TaskOfTResult_MethodAsync()
Dim intResult As Integer = Await returnedTaskTResult
' or, in a single statement
Dim intResult As Integer = Await TaskOfTResult_MethodAsync()

' Signature specifies Task
Async Function Task_MethodAsync() As Task

    ' . . .
    ' The method has no return statement.
End Function

' Calls to Task_MethodAsync
Task returnedTask = Task_MethodAsync()
Await returnedTask
' or, in a single statement
Await Task_MethodAsync()

Elke geretourneerde taak vertegenwoordigt doorlopend werk. Een taak bevat informatie over de status van het asynchrone proces en uiteindelijk het uiteindelijke resultaat van het proces of de uitzondering die het proces genereert als het niet lukt.

Een asynchrone methode kan ook een Sub methode zijn. Dit retourtype wordt voornamelijk gebruikt om gebeurtenis-handlers te definiëren, waarbij een retourtype vereist is. Asynchrone gebeurtenishandlers dienen vaak als uitgangspunt voor asynchrone programma's.

Een asynchrone methode die een Sub procedure is, kan niet worden afgewacht en de aanroeper kan geen uitzonderingen vangen die de methode werpt.

Een asynchrone methode kan geen ByRef-parameters declareren, maar de methode kan methoden aanroepen die dergelijke parameters hebben.

Zie Asynchrone retourtypen (Visual Basic) voor meer informatie en voorbeelden. Voor meer informatie over het vangen van uitzonderingen in asynchrone methoden, zie Try...Catch...Finally-instructie.

Asynchrone API's in Windows Runtime-programmering hebben een van de volgende retourtypen, die vergelijkbaar zijn met taken:

Zie Asynchrone API's aanroepen in C# of Visual Basic voor meer informatie en een voorbeeld.

Naamgevingsconventie

Volgens de conventie voegt u 'Async' toe aan de namen van methoden die een Async wijzigingsfunctie hebben.

U kunt de conventie negeren waarbij een gebeurtenis, basisklasse of interfacecontract een andere naam voorstelt. U moet bijvoorbeeld de naam van algemene gebeurtenishandlers niet wijzigen, zoals Button1_Click.

Verwante onderwerpen en voorbeelden (Visual Studio)

Titel Beschrijving Voorbeeld
Overzicht: toegang tot internet met behulp van Async and Await (Visual Basic) Laat zien hoe u een synchrone WPF-oplossing converteert naar een asynchrone WPF-oplossing. De toepassing downloadt een reeks websites. Asynchroon voorbeeld: Asynchroon programmeren met Async en Await (Visual Basic)
Procedure: Het overzicht van Async uitbreiden met behulp van Task.WhenAll (Visual Basic) Voegt Task.WhenAll toe aan de vorige stap-voor-stap handleiding. Het gebruik van WhenAll start alle downloads tegelijkertijd.
Procedure: Meerdere webaanvragen parallel maken met behulp van Async en Await (Visual Basic) Demonstreert hoe u meerdere taken tegelijk start. Asynchroon voorbeeld: Meerdere webaanvragen parallel maken
Asynchrone retourtypen (Visual Basic) Illustreert de typen die asynchrone methoden kunnen retourneren en legt uit wanneer elk type geschikt is.
Besturing van de stroom in Asynchrone programma's (Visual Basic) Spoort in detail de stroom van besturing door een reeks van wachtexpressies in een asynchroon programma. Async-voorbeeld: Controlestroom in Async-programma's
Fine-Tuning uw asynchrone toepassing (Visual Basic) Laat zien hoe u de volgende functionaliteit toevoegt aan uw asynchrone oplossing:

- Een asynchrone taak of een lijst met taken annuleren (Visual Basic)
- Asynchrone taken annuleren na een periode (Visual Basic)
- Overblijvende asynchrone taken annuleren nadat één is voltooid (Visual Basic)
- Meerdere asynchrone taken starten en deze verwerken wanneer ze zijn voltooid (Visual Basic)
Async-voorbeeld: Uw toepassing verfijnen
Reentrancy bij Async Apps verwerken (Visual Basic) Laat zien hoe u gevallen verwerkt waarin een actieve asynchrone bewerking opnieuw wordt gestart terwijl deze wordt uitgevoerd.
WhenAny: Bridging tussen .NET Framework en Windows Runtime Laat zien hoe u een brug maakt tussen taaktypen in .NET Framework en IAsyncOperations in Windows Runtime, zodat u WhenAny kunt gebruiken met een Windows Runtime-methode. Async-voorbeeld: Overbrugging tussen .NET en Windows Runtime (AsTask en WhenAny)
Asynchrone annulering: Overbrugging tussen .NET Framework en Windows Runtime Laat zien hoe u een brug maakt tussen taaktypen in .NET Framework en IAsyncOperations in Windows Runtime, zodat u CancellationTokenSource kunt gebruiken met een Windows Runtime-methode. Async-voorbeeld: Overbrugging tussen .NET en Windows Runtime (AsTask & Annuleren)
Async gebruiken voor Bestandstoegang (Visual Basic) Laat de voordelen zien van het gebruik van async en await voor toegang tot bestanden.
Asynchroon patroon op basis van taken (TAP) Beschrijft een nieuw patroon voor asynchroon in .NET Framework. Het patroon is gebaseerd op de typen Task en Task(Of TResult).

Volledig voorbeeld

De volgende code is het MainWindow.xaml.vb bestand van de WPF-toepassing (Windows Presentation Foundation) die in dit onderwerp wordt besproken. U kunt het voorbeeld downloaden uit Async Sample: Voorbeeld van Asynchroon programmeren met Async en Await.


Imports System.Net.Http

' Example that demonstrates Asynchronous Programming with Async and Await.
' It uses HttpClient.GetStringAsync to download the contents of a website.
' Sample Output:
' Working . . . . . . .
'
' Length of the downloaded string: 39678.

Class MainWindow

    ' Mark the event handler with Async so you can use Await in it.
    Private Async Sub StartButton_Click(sender As Object, e As RoutedEventArgs)

        ' Call and await immediately.
        ' StartButton_Click suspends until AccessTheWebAsync is done.
        Dim contentLength As Integer = Await AccessTheWebAsync()

        ResultsTextBox.Text &= $"{vbCrLf}Length of the downloaded string: {contentLength}.{vbCrLf}"

    End Sub


    ' Three things to note about writing an Async Function:
    '  - The function has an Async modifier.
    '  - Its return type is Task or Task(Of T). (See "Return Types" section.)
    '  - As a matter of convention, its name ends in "Async".
    Async Function AccessTheWebAsync() As Task(Of Integer)

        Using client As New HttpClient()

            ' Call and await separately.
            '  - AccessTheWebAsync can do other things while GetStringAsync is also running.
            '  - getStringTask stores the task we get from the call to GetStringAsync.
            '  - Task(Of String) means it is a task which returns a String when it is done.
            Dim getStringTask As Task(Of String) =
                client.GetStringAsync("https://learn.microsoft.com/dotnet")

            ' You can do other work here that doesn't rely on the string from GetStringAsync.
            DoIndependentWork()

            ' The Await operator suspends AccessTheWebAsync.
            '  - AccessTheWebAsync does not continue until getStringTask is complete.
            '  - Meanwhile, control returns to the caller of AccessTheWebAsync.
            '  - Control resumes here when getStringTask is complete.
            '  - The Await operator then retrieves the String result from getStringTask.
            Dim urlContents As String = Await getStringTask

            ' The Return statement specifies an Integer result.
            ' A method which awaits AccessTheWebAsync receives the Length value.
            Return urlContents.Length

        End Using

    End Function

    Sub DoIndependentWork()
        ResultsTextBox.Text &= $"Working . . . . . . .{vbCrLf}"
    End Sub

End Class

Zie ook