Asynchrone programmering met Async en Await (Visual Basic)
U kunt prestatieknelpunten 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 de .NET Framework 4,5 en hoger en in de 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. 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 mogelijk blokkerende taak is voltooid.
In de volgende tabel ziet u typische gebieden waar asynchrone programmering de reactiesnelheid verbetert. De vermelde API's uit de .NET Framework 4.5 en de 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, BitmapEncoder, BitmapDecoder |
WCF-programmering | Synchrone en asynchrone bewerkingen |
Asynchrony is vooral 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 deze in plaats daarvan 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 tot deze 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 de .NET Framework of de 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 van Async
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 aangeroepen die u toevoegt om de asynchrone bewerking te maken.
U vindt een volledig Windows Presentation Foundation voorbeeldbestand (WPF) 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://docs.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
er geen werk is dat het kan doen tussen het aanroepen GetStringAsync
en wachten op voltooiing ervan, kunt u uw code vereenvoudigen door de volgende 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
wijzigingsfunctie.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 TResult heeft getypt.
- 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 aangeeft waarop de methode niet kan worden voortgezet totdat de verwachte asynchrone bewerking is voltooid. Ondertussen wordt de methode onderbroken en keert het besturingselement 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 Asynchroon programmeren voor meer informatie over asynchrone .NET Framework in eerdere versies van de .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:
De getallen in het diagram komen overeen met de volgende stappen:
Een gebeurtenis-handler roept aan en wacht op de
AccessTheWebAsync
asynchrone methode.AccessTheWebAsync
maakt een HttpClient exemplaar en roept de GetStringAsync asynchrone methode aan om de inhoud van een website als tekenreeks te downloaden.Er gebeurt iets waarin
GetStringAsync
de voortgang wordt onderbroken. Misschien moet het wachten tot een website is gedownload of een andere blokkeringsactiviteit. Om te voorkomen dat resources worden geblokkeerd,GetStringAsync
geeft u de controle over de aanroeper.AccessTheWebAsync
GetStringAsync
retourneert een taak (van TResult) waarbij TResult een tekenreeks is enAccessTheWebAsync
wijst de taak toe aan degetStringTask
variabele. De taak vertegenwoordigt het lopende proces voor de aanroep naarGetStringAsync
, met een toezegging om een werkelijke tekenreekswaarde te produceren wanneer het werk is voltooid.Omdat
getStringTask
nog niet is gewacht,AccessTheWebAsync
kunt u doorgaan met ander werk dat niet afhankelijk is van het uiteindelijke resultaat vanGetStringAsync
. Dat werk wordt vertegenwoordigd door een aanroep naar de synchrone methodeDoIndependentWork
.DoIndependentWork
is een synchrone methode die het werk uitvoert en terugkeert naar de aanroeper.AccessTheWebAsync
heeft geen werk meer dat het kan doen zonder een resultaat vangetStringTask
.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.AccessTheWebAsync
Maakt daarom gebruik van een wachtoperator om de voortgang ervan op te schorten en de controle over te brengen naar de methode die wordt aangeroepenAccessTheWebAsync
.AccessTheWebAsync
retourneert een aanroeperTask(Of Integer)
. De taak vertegenwoordigt een belofte om een geheel getal te produceren dat de lengte van de gedownloade tekenreeks is.Notitie
Als
GetStringAsync
(en daaromgetStringTask
) is voltooid voordatAccessTheWebAsync
deze wordt gewacht, blijft de controle inAccessTheWebAsync
. De kosten voor het onderbreken en vervolgens terugkerenAccessTheWebAsync
naar worden verspild als het aangeroepen asynchrone proces (getStringTask
) al is voltooid en 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 op dat resultaat wacht, of de beller kan onmiddellijk wachten. De gebeurtenis-handler wacht opAccessTheWebAsync
enAccessTheWebAsync
wacht opGetStringAsync
.GetStringAsync
voltooit en produceert een tekenreeksresultaat. Het tekenreeksresultaat wordt niet geretourneerd door de aanroep naarGetStringAsync
de manier die u zou verwachten. (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 await-operator haalt het resultaat op vangetStringTask
. Met de toewijzingsinstructie wordt het opgehaalde resultaat toegewezen aanurlContents
.Wanneer
AccessTheWebAsync
het tekenreeksresultaat is, kan de methode de lengte van de tekenreeks berekenen. Dan is het werkAccessTheWebAsync
ook voltooid en kan de wacht gebeurtenis-handler 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 het verschil tussen synchroon en asynchroon gedrag te overwegen als u geen asynchrone programmering hebt. 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 Control Flow in Async Programs (Visual Basic) voor meer informatie over de controlestroom.
Asynchrone API-methoden
U vraagt zich misschien af waar u methoden kunt vinden, zoals GetStringAsync
die ondersteuning bieden voor asynchrone programmering. De .NET Framework 4,5 of hoger bevat veel leden die met Async
enAwait
. U kunt deze leden herkennen door het achtervoegsel 'Async' dat is gekoppeld aan de naam van het lid en een retourtype of Tasktaak (van 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 de .NET Framework en de Windows Runtime voor meer informatie en voorbeeldmethoden.
Threads
Asynchrone methoden zijn bedoeld als niet-blokkerende bewerkingen. Een Await
expressie in een asynchrone methode blokkeert de huidige thread niet terwijl de verwachte taak wordt uitgevoerd. In plaats daarvan registreert de expressie de rest van de methode als vervolg en retourneert 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 multi-threading 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 wacht tot er resultaten beschikbaar zijn.
De asynchrone benadering van asynchrone programmering verdient de voorkeur aan bestaande benaderingen in vrijwel elk geval. 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 hangpunten aan te wijzen. De wachtoperator vertelt de compiler dat de asynchrone methode pas na dat punt kan doorgaan als het verwachte asynchrone proces is voltooid. Ondertussen keert het besturingselement terug naar de aanroeper van de asynchrone methode.
De schorsing van een asynchrone methode bij een
Await
expressie vormt geen exit van de methode enFinally
blokken worden niet uitgevoerd.De gemarkeerde asynchrone methode kan zelf worden verwacht door methoden die deze aanroepen.
Een asynchrone methode bevat meestal 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 ophangpunt te markeren, wordt de methode uitgevoerd als een synchrone methode, ondanks de Async
modifier. De compiler geeft een waarschuwing voor dergelijke methoden.
Async
en Await
contextuele trefwoorden zijn. Zie de volgende onderwerpen voor meer informatie en voorbeelden:
Retourtypen en parameters
In .NET Framework programmeren 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 door een aanroep naar een andere asynchrone methode.
U geeft Taak (van TResult) op als het retourtype als de methode een Return-instructie bevat die een operand van het type TResult
specificeert.
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 declareert en aanroept die een taak (van TResult) 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 gebeurtenis-handlers fungeren vaak als uitgangspunt voor asynchrone programma's.
Een asynchrone methode die een Sub
procedure is, kan niet worden gewacht en de aanroeper kan geen uitzonderingen vangen die de methode genereert.
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. Zie Try voor meer informatie over het ondervangen van uitzonderingen in asynchrone methoden ... Vangen... Tot slot verklaring.
Asynchrone API's in Windows Runtime programmeren hebben een van de volgende retourtypen, die vergelijkbaar zijn met taken:
- IAsyncOperation(van TResult), die overeenkomt met Task(Of TResult)
- IAsyncAction, die overeenkomt met Task
- IAsyncActionWithProgress(van TProgress)
- IAsyncOperationWithProgress(van TResult, TProgress)
Zie Asynchrone API's aanroepen in C# of Visual Basic voor meer informatie en een voorbeeld.
Naming
Standaard 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 gebeurtenis-handlers niet wijzigen, zoals Button1_Click
.
Verwante onderwerpen en voorbeelden (Visual Studio)
Titel | Beschrijving | Voorbeeld |
---|---|---|
Overzicht: toegang tot het web met behulp van Async en 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: De Asynchrone walkthrough uitbreiden met behulp van Task.WhenAll (Visual Basic) | Wordt toegevoegd Task.WhenAll aan het vorige scenario. Het gebruik van WhenAll alle downloads tegelijk wordt gestart. |
|
Procedure: Meerdere webaanvragen parallel maken met behulp van Async en Await (Visual Basic) | Laat zien 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. | |
Beheer Flow in Asynchrone programma's (Visual Basic) | Traceert in detail de controlestroom via een opeenvolgende wachtexpressies in een asynchroon programma. | Async-voorbeeld: Flow beheren in Asynchrone programma's |
Uw asynchrone toepassing (Visual Basic) afstemmen | 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) - Resterende asynchrone taken annuleren nadat een taak is voltooid (Visual Basic) - Meerdere asynchrone taken starten en deze verwerken wanneer ze zijn voltooid (Visual Basic) |
Asynchroon voorbeeld: Uw toepassing verfijnen |
Reentrancy verwerken in Async-apps (Visual Basic) | Laat zien hoe u gevallen kunt afhandelen waarin een actieve asynchrone bewerking opnieuw wordt gestart terwijl deze wordt uitgevoerd. | |
WhenAny: Bridging tussen de .NET Framework en de Windows Runtime | Hier ziet u hoe u in de Windows Runtime een brug kunt maken tussen taaktypen in de .NET Framework en IAsyncOperations, zodat u deze kunt gebruiken WhenAny met een Windows Runtime methode. | Async-voorbeeld: Bridging tussen .NET en Windows Runtime (AsTask en WhenAny) |
Asynchrone annulering: Bridging tussen de .NET Framework en de Windows Runtime | Hier ziet u hoe u in de Windows Runtime een brug kunt maken tussen taaktypen in de .NET Framework en IAsyncOperations, zodat u deze kunt gebruiken CancellationTokenSource met een Windows Runtime methode. | Async-voorbeeld: Bridging tussen .NET en Windows Runtime (AsTask-annulering&) |
Async gebruiken voor bestandstoegang (Visual Basic) | Lijsten en demonstreert de voordelen van het gebruik van asynchroon en wachten op toegang tot bestanden. | |
Asynchroon Asynchroon patroon (TAP) op basis van taken | Beschrijft een nieuw patroon voor asynchroon in de .NET Framework. Het patroon is gebaseerd op de Task typen Taak(van TResult). | |
Asynchrone video's op Channel 9 | Biedt koppelingen naar verschillende video's over asynchrone programmering. |
Volledig voorbeeld
De volgende code is het Bestand MainWindow.xaml.vb uit 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 Progamming 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://docs.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