Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
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 använde för att göra, och ditt program 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 supportavsnitt 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 kommer åt webben. Åtkomsten till en webbresurs är ibland långsam eller fördröjd. Om en sådan aktivitet blockeras inom 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.
Följande tabell visar typiska områden där asynkron programmering förbättrar svarstiden. De listade API:erna från .NET Framework 4.5 och Windows Runtime innehåller metoder som stöder asynkron programmering.
Programområde | Api:er som stöder asynkrona metoder |
---|---|
Webbtillgång | HttpClient, SyndicationClient |
Arbeta med filer | StorageFile, StreamWriter, , StreamReaderXmlReader |
Arbeta med bilder | MediaCapture, , BitmapEncoderBitmapDecoder |
WCF-programmering | synkrona och asynkrona åtgärder |
Asynkronhet visar sig vara särskilt värdefullt för program som har åtkomst till användargränssnittstråden eftersom all användargränssnittsrelaterad 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 misslyckades 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 över alternativ som du kan välja mellan när du utformar asynkrona åtgärder. Det innebär att du får alla fördelar med traditionell asynkron programmering men med mycket mindre arbete 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 av Async
och Await
kallas async-metoder.
I följande exempel visas en asynkron metod. Nästan allt i koden bör se helt bekant ut för dig. Kommentarerna belyser de funktioner som du lägger till för att skapa asynkron.
Du hittar en komplett WPF-exempelfil (Windows Presentation Foundation) 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://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
Om det inte finns något arbete som AccessTheWebAsync
kan utföra mellan att du anropar GetStringAsync
och väntar på dess fullbordande, 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 retur-instruktion 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 hänvisas till "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 visar 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 väntepunkt 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 du skulle göra i en synkron lösning, och problemet är löst.
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å asynkron
AccessTheWebAsync
metod.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 framsteg. Kanske måste den vänta tills en webbplats laddas ned eller någon annan blockerande aktivitet. För att undvika att blockera resurserGetStringAsync
ger kontroll till anroparen,AccessTheWebAsync
.GetStringAsync
returnerar en aktivitet (av 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äntats på ä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 inget arbete kvar att utfö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.Därför använder
AccessTheWebAsync
en await-operator för att pausa dess framsteg och för att överföra kontrollen till metoden som anropadeAccessTheWebAsync
.AccessTheWebAsync
returnerar enTask(Of Integer)
till anroparen. Uppgiften innebär ett löfte om att producera ett heltalsresultat som är längden på den nedladdade strängen.Anmärkning
Om
GetStringAsync
(och därförgetStringTask
) har slutförts innanAccessTheWebAsync
inväntar det, förblir kontrollen iAccessTheWebAsync
. Kostnaden för att pausa och sedan återgå tillAccessTheWebAsync
skulle slösas bort om den så kallade asynkrona processen (getStringTask
) redan har slutförts och AccessTheWebSync inte behöver vänta på det slutliga resultatet.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 du 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ör och genererar 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 arbetet medAccessTheWebAsync
också slutfört och den väntande händelsehanteraren kan fortsätta. 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 är nybörjare på asynkron programmering tar det en minut att tänka på 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 asynkron metoden så småningom slutför sitt arbete markeras uppgiften som slutförd och resultatet, om det finns något, lagras i aktiviteten.
Mer information om kontrollflöde finns i Kontrollflöde i Async-program (Visual Basic).
API Async-metoder
Du kanske undrar var du hittar metoder som den som GetStringAsync
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 knutet 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 synkrona metoder 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. Asynkrona metoder kräver inte flera trådar eftersom en asynkron metod inte körs på en egen tråd. Metoden körs i den aktuella synkroniseringskontexten och använder endast tid i tråden 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 async-baserade metoden för asynkron programmering är att föredra framför de befintliga metoderna 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 separerar 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 asynkrona metoden kan använda Await för att ange upphängningspunkter. Await-operatorn meddelar kompilatorn att asynkron metod inte kan fortsätta förbi den punkten förrän den inväntade asynkrona processen har slutförts. Under tiden återgår kontrollen till anroparen för async-metoden.
Avstängningen av en asynkron metod vid ett
Await
uttryck utgör inte ett avslut från metoden ochFinally
block körs inte.De markerade asynkrona metoderna kan själva inväntas av metoder som anropar dem.
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 fjädringspunkt körs metoden som en synkron metod gör, 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 Return-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 det slutliga resultatet från processen eller undantaget 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. Asynkrona händelsehanterare fungerar ofta som startpunkt för asynkrona program.
Det går inte att invänta en asynkron metod som är en Sub
procedur; anroparen kan inte hantera några undantag som metoden genererar.
En asynkron 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 ett 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 den MainWindow.xaml.vb fil från WPF-programmet (Windows Presentation Foundation) som beskrivs i det här avsnittet. Du kan ladda ned exemplet från Async Sample: Exempel från "Asynkron programmering med Async och 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