Asynkron programmering med Async och Await (Visual Basic)
Du kan undvika flaskhalsar i prestanda och förbättra programmets övergripande svarstider med hjälp av asynkron programmering. Traditionella tekniker för att skriva asynkrona program kan dock vara komplicerade, vilket gör dem svåra att skriva, felsöka och underhålla.
Visual Studio 2012 introducerade en förenklad metod, asynkron programmering, som utnyttjar asynkront stöd i .NET Framework 4.5 och senare samt i Windows Runtime. Kompilatorn utför det svåra arbete som utvecklaren brukade göra, och programmet behåller en logisk struktur som liknar synkron kod. Därför får du alla fördelar med asynkron programmering med en bråkdel av arbetet.
Det här avsnittet innehåller en översikt över när och hur du använder asynkron programmering och innehåller länkar till supportämnen som innehåller information och exempel.
Async förbättrar svarstiden
Asynkron är viktigt för aktiviteter som potentiellt blockerar, till exempel när ditt program ansluter till webben. Åtkomsten till en webbresurs är ibland långsam eller fördröjd. Om en sådan aktivitet blockeras i en synkron process måste hela programmet vänta. I en asynkron process kan programmet fortsätta med annat arbete som inte är beroende av webbresursen förrän den potentiellt blockerande uppgiften har slutförts.
I följande tabell visas typiska områden där asynkron programmering förbättrar svarstiden. Api:erna i listan från .NET Framework 4.5 och Windows Runtime innehåller metoder som stöder asynkron programmering.
Programområde | Stöd för API:er som innehåller asynkrona metoder |
---|---|
Webbåtkomst | HttpClient, SyndicationClient |
Arbeta med filer | StorageFile, StreamWriter, StreamReader, XmlReader |
Arbeta med bilder | MediaCapture, BitmapEncoder, BitmapDecoder |
WCF-programmering | Synkrona och asynkrona åtgärder |
Asynkron teknik visar sig vara särskilt värdefull för program som har åtkomst till UI-tråden eftersom all UI-relaterad aktivitet vanligtvis delar en tråd. Om någon process blockeras i ett synkront program blockeras alla. Programmet slutar svara och du kan dra slutsatsen att det har misslyckats när det i stället bara väntar.
När du använder asynkrona metoder fortsätter programmet att svara på användargränssnittet. Du kan till exempel ändra storlek på eller minimera ett fönster, eller stänga programmet om du inte vill vänta tills det har slutförts.
Den asynkrona metoden lägger till motsvarigheten till en automatisk överföring i listan med alternativ som du kan välja mellan när du utformar asynkrona åtgärder. Du får alltså alla fördelar med traditionell asynkron programmering, men med mycket mindre ansträngning från utvecklaren.
Asynkrona metoder är enklare att skriva
Nyckelorden Async och Await i Visual Basic är kärnan i asynkron programmering. Genom att använda dessa två nyckelord kan du använda resurser i .NET Framework eller Windows Runtime för att skapa en asynkron metod nästan lika enkelt som du skapar en synkron metod. Asynkrona metoder som du definierar med hjälp Async
av och Await
kallas asynkrona metoder.
I följande exempel visas en asynkron metod. Nästan allt i koden bör se helt bekant ut för dig. Kommentarerna beskriver de funktioner som du lägger till för att skapa asynkron.
Du hittar en fullständig Windows Presentation Foundation -exempelfil (WPF) i slutet av det här avsnittet och du kan ladda ned exemplet från Async Sample: Example from "Asynchronous Programming with Async and 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
Om AccessTheWebAsync
det inte finns något arbete som kan utföras mellan att anropa GetStringAsync
och vänta på att koden ska slutföras, kan du förenkla koden genom att anropa och vänta i följande enda instruktion.
Dim urlContents As String = Await client.GetStringAsync()
Följande egenskaper sammanfattar vad som gör föregående exempel till en asynkron metod:
Metodsignaturen innehåller en
Async
modifierare.Namnet på en asynkron metod, enligt konvention, slutar med suffixet "Async".
Returtypen är en av följande typer:
- Task(Of TResult) om metoden har en retursats där operanden har typen TResult.
- Task om metoden inte har någon retursats eller har en retursats utan operand.
- Sub om du skriver en asynkron händelsehanterare.
Mer information finns i "Returtyper och parametrar" senare i det här avsnittet.
Metoden innehåller vanligtvis minst ett await-uttryck, vilket markerar en punkt där metoden inte kan fortsätta förrän den väntade asynkrona åtgärden har slutförts. Under tiden pausas metoden och kontrollen återgår till metodens anropare. Nästa avsnitt i det här avsnittet illustrerar vad som händer vid avstängningspunkten.
I asynkrona metoder använder du de angivna nyckelorden och typerna för att ange vad du vill göra, och kompilatorn gör resten, inklusive att hålla reda på vad som måste hända när kontrollen återgår till en await-punkt i en pausad metod. Vissa rutinprocesser, till exempel loopar och undantagshantering, kan vara svåra att hantera i traditionell asynkron kod. I en asynkron metod skriver du dessa element ungefär som i en synkron lösning, och problemet löses.
Mer information om asynkron i tidigare versioner av .NET Framework finns i TPL och Traditionell .NET Framework Asynkron programmering.
Vad händer i en Async-metod
Det viktigaste att förstå i asynkron programmering är hur kontrollflödet flyttas från metod till metod. Följande diagram leder dig genom processen:
Siffrorna i diagrammet motsvarar följande steg:
En händelsehanterare anropar och väntar på
AccessTheWebAsync
metoden async.AccessTheWebAsync
skapar en HttpClient instans och anropar den GetStringAsync asynkrona metoden för att ladda ned innehållet på en webbplats som en sträng.Något händer i
GetStringAsync
som pausar dess förlopp. Den kanske måste vänta tills en webbplats har laddats ned eller någon annan blockerande aktivitet. För att undvika att blockera resurserGetStringAsync
ger kontroll till anroparen,AccessTheWebAsync
.GetStringAsync
returnerar en Task(Of TResult) där TResult är en sträng ochAccessTheWebAsync
tilldelar aktiviteten till variabelngetStringTask
. Uppgiften representerar den pågående processen för anropet tillGetStringAsync
, med ett åtagande att skapa ett verkligt strängvärde när arbetet är klart.Eftersom
getStringTask
inte har väntat ännu kanAccessTheWebAsync
fortsätta med annat arbete som inte är beroende av slutresultatet frånGetStringAsync
. Det arbetet representeras av ett anrop till den synkrona metodenDoIndependentWork
.DoIndependentWork
är en synkron metod som utför sitt arbete och återgår till anroparen.AccessTheWebAsync
har slut på arbete som det kan göra utan ett resultat frångetStringTask
.AccessTheWebAsync
vill sedan beräkna och returnera längden på den nedladdade strängen, men metoden kan inte beräkna det värdet förrän metoden har strängen.AccessTheWebAsync
Därför använder en await-operator för att pausa förloppet och för att ge kontroll till metoden som anropadeAccessTheWebAsync
.AccessTheWebAsync
returnerar enTask(Of Integer)
till anroparen. Uppgiften representerar ett löfte om att skapa ett heltalsresultat som är längden på den nedladdade strängen.Anteckning
Om
GetStringAsync
(och därförgetStringTask
) har slutförts innanAccessTheWebAsync
det väntar, finns kontrollen kvar iAccessTheWebAsync
. Kostnaden för att pausa och sedan återgå tillAccessTheWebAsync
skulle gå förlorad om den anropade asynkrona processen (getStringTask
) redan har slutförts och AccessTheWebSync inte behöver vänta på slutresultatet.I anroparen (händelsehanteraren i det här exemplet) fortsätter bearbetningsmönstret. Anroparen kan utföra annat arbete som inte är beroende av resultatet från
AccessTheWebAsync
innan den väntar på det resultatet, eller så kan anroparen vänta omedelbart. Händelsehanteraren väntar påAccessTheWebAsync
ochAccessTheWebAsync
väntar påGetStringAsync
.GetStringAsync
slutförs och skapar ett strängresultat. Strängresultatet returneras inte av anropet tillGetStringAsync
på det sätt som du kan förvänta dig. (Kom ihåg att metoden redan returnerade en uppgift i steg 3.) I stället lagras strängresultatet i uppgiften som representerar slutförandet av metoden ,getStringTask
. Await-operatorn hämtar resultatet frångetStringTask
. Tilldelningssatsen tilldelar det hämtade resultatet tillurlContents
.När
AccessTheWebAsync
har strängresultatet kan metoden beräkna längden på strängen. Sedan är arbetetAccessTheWebAsync
med också slutfört och den väntande händelsehanteraren kan återupptas. I det fullständiga exemplet i slutet av ämnet kan du bekräfta att händelsehanteraren hämtar och skriver ut värdet för längdresultatet.
Om du inte har använt asynkron programmering tidigare kan det ta en minut att överväga skillnaden mellan synkront och asynkront beteende. En synkron metod returnerar när dess arbete är klart (steg 5), men en asynkron metod returnerar ett aktivitetsvärde när dess arbete pausas (steg 3 och 6). När metoden async så småningom slutför sitt arbete markeras uppgiften som slutförd och resultatet, om det finns, lagras i aktiviteten.
Mer information om kontrollflöde finns i Kontrollera Flow i Async-program (Visual Basic).
API Async-metoder
Du kanske undrar var du hittar metoder som GetStringAsync
som stöder asynkron programmering. .NET Framework 4.5 eller senare innehåller många medlemmar som arbetar med Async
och Await
. Du kan känna igen dessa medlemmar med suffixet "Async" som är kopplat till medlemsnamnet och en returtyp av Task eller Task(Of TResult). Klassen innehåller till exempel System.IO.Stream
metoder som CopyToAsync, ReadAsyncoch WriteAsync tillsammans med de synkrona metoderna CopyTo, Readoch Write.
Windows Runtime innehåller också många metoder som du kan använda med Async
och Await
i Windows appar. Mer information och exempelmetoder finns i Anropa asynkrona API:er i C# eller Visual Basic, Asynkron programmering (Windows Runtime appar) och WhenAny: Bryggning mellan .NET Framework och Windows Runtime.
Trådar
Asynkrona metoder är avsedda att vara icke-blockerande åtgärder. Ett Await
uttryck i en asynkron metod blockerar inte den aktuella tråden medan den väntade aktiviteten körs. I stället registrerar uttrycket resten av metoden som en fortsättning och returnerar kontrollen till anroparen för async-metoden.
Nyckelorden Async
och Await
orsakar inte att ytterligare trådar skapas. Async-metoder kräver inte multitrådning eftersom en asynkron metod inte körs på en egen tråd. Metoden körs på den aktuella synkroniseringskontexten och använder tid på tråden endast när metoden är aktiv. Du kan använda Task.Run för att flytta CPU-bundet arbete till en bakgrundstråd, men en bakgrundstråd hjälper inte till med en process som bara väntar på att resultaten ska bli tillgängliga.
Den asynkrona metoden för asynkron programmering är att föredra framför befintliga metoder i nästan alla fall. I synnerhet är den här metoden bättre än BackgroundWorker för I/O-bundna åtgärder eftersom koden är enklare och du inte behöver skydda dig mot konkurrensförhållanden. I kombination med Task.Runär asynkron programmering bättre än BackgroundWorker för CPU-bundna åtgärder eftersom asynkron programmering skiljer samordningsinformationen för att köra koden från det arbete som Task.Run
överförs till trådpoolen.
Async och Await
Om du anger att en metod är en asynkron metod med hjälp av en Async-modifierare aktiverar du följande två funktioner.
Den markerade metoden async kan använda Await för att ange upphängningspunkter. Await-operatorn meddelar kompilatorn att async-metoden inte kan fortsätta förbi den punkten förrän den väntade asynkrona processen har slutförts. Under tiden återgår kontrollen till anroparen för async-metoden.
Avstängningen av en asynkron metod i ett
Await
uttryck utgör inte ett avslut från metoden ochFinally
block körs inte.Den markerade async-metoden kan i sig inväntas av metoder som anropar den.
En asynkron metod innehåller vanligtvis en eller flera förekomster av en Await
operator, men avsaknaden av Await
uttryck orsakar inte ett kompilatorfel. Om en asynkron metod inte använder en Await
operator för att markera en upphängningspunkt körs metoden som en synkron metod, trots Async
modifieraren. Kompilatorn utfärdar en varning för sådana metoder.
Async
och Await
är kontextuella nyckelord. Mer information och exempel finns i följande avsnitt:
Returnera typer och parametrar
I .NET Framework programmering returnerar en asynkron metod vanligtvis en Task eller en aktivitet (Av TResult). I en asynkron metod tillämpas en Await
operator på en aktivitet som returneras från ett anrop till en annan asynkron metod.
Du anger Task(Of TResult) som returtyp om metoden innehåller en Retur-instruktion som anger en operand av typen TResult
.
Du använder Task
som returtyp om metoden inte har någon retursats eller har en retursats som inte returnerar en operand.
I följande exempel visas hur du deklarerar och anropar en metod som returnerar en aktivitet (av TResult) eller en 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()
Varje returnerad uppgift representerar pågående arbete. En uppgift kapslar in information om tillståndet för den asynkrona processen och slutligen antingen slutresultatet från processen eller det undantag som processen genererar om den inte lyckas.
En asynkron metod kan också vara en Sub
metod. Den här returtypen används främst för att definiera händelsehanterare, där en returtyp krävs. Async-händelsehanterare fungerar ofta som utgångspunkt för asynkrona program.
Det går inte att vänta på en asynkron metod som är en Sub
procedur och anroparen kan inte fånga några undantag som metoden genererar.
En async-metod kan inte deklarera ByRef-parametrar , men metoden kan anropa metoder som har sådana parametrar.
Mer information och exempel finns i Async Return Types (Visual Basic). Mer information om hur du fångar undantag i asynkrona metoder finns i Prova... Fånga... Slutligen -instruktion.
Asynkrona API:er i Windows Runtime programmering har någon av följande returtyper, som liknar uppgifter:
- IAsyncOperation(Of TResult), som motsvarar Task(Of TResult)
- IAsyncAction, vilket motsvarar Task
- IAsyncActionWithProgress(av TProgress)
- IAsyncOperationWithProgress(av TResult, TProgress)
Mer information och ett exempel finns i Anropa asynkrona API:er i C# eller Visual Basic.
Namnkonvention
Enligt konventionen lägger du till "Async" i namnen på metoder som har en Async
modifierare.
Du kan ignorera konventionen där en händelse, basklass eller gränssnittskontrakt föreslår ett annat namn. Du bör till exempel inte byta namn på vanliga händelsehanterare, till exempel Button1_Click
.
Relaterade ämnen och exempel (Visual Studio)
Fullständigt exempel
Följande kod är filen MainWindow.xaml.vb från Windows Presentation Foundation-programmet (WPF) som beskrivs i det här avsnittet. Du kan ladda ned exemplet från Async Sample: Exempel från "Asynchronous Programming with Async and 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