Dela via


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 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:

Diagram som visar spårning av ett asynkront program.

Siffrorna i diagrammet motsvarar följande steg:

  1. En händelsehanterare anropar och väntar på asynkron AccessTheWebAsync metod.

  2. 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.

  3. 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 resurser GetStringAsync ger kontroll till anroparen, AccessTheWebAsync.

    GetStringAsync returnerar en aktivitet (av TResult) där TResult är en sträng och AccessTheWebAsync tilldelar aktiviteten till variabeln getStringTask . Uppgiften representerar den pågående processen för anropet till GetStringAsync, med ett åtagande att skapa ett verkligt strängvärde när arbetet är klart.

  4. Eftersom getStringTask inte har väntats på ännu, kan AccessTheWebAsync fortsätta med annat arbete som inte är beroende av slutresultatet från GetStringAsync. Det arbetet representeras av ett anrop till den synkrona metoden DoIndependentWork.

  5. DoIndependentWork är en synkron metod som utför sitt arbete och återgår till anroparen.

  6. AccessTheWebAsync har inget arbete kvar att utföra utan ett resultat från getStringTask. 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 anropade AccessTheWebAsync. AccessTheWebAsync returnerar en Task(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ör getStringTask) har slutförts innan AccessTheWebAsync inväntar det, förblir kontrollen i AccessTheWebAsync. Kostnaden för att pausa och sedan återgå till AccessTheWebAsync 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, och AccessTheWebAsync väntar på GetStringAsync.

  7. GetStringAsync slutför och genererar ett strängresultat. Strängresultatet returneras inte av anropet till GetStringAsync 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ån getStringTask. Tilldelningssatsen tilldelar det hämtade resultatet till urlContents.

  8. När AccessTheWebAsync har strängresultatet kan metoden beräkna längden på strängen. Sedan är arbetet med AccessTheWebAsync 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 och Finally 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:

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)

Titel Beskrivning Exempel
Genomgång: Åtkomst till webben med hjälp av Async och Await (Visual Basic) Visar hur du konverterar en synkron WPF-lösning till en asynkron WPF-lösning. Programmet laddar ned en serie webbplatser. Async-exempel: Asynkron programmering med Async och Await (Visual Basic)
Gör så här: Utöka Async-genomgången med hjälp av Task.WhenAll (Visual Basic) Lägger Task.WhenAll till i föregående genomgång. Användningen av WhenAll startar alla nedladdningar samtidigt.
Gör så här: Gör flera webbbegäranden parallellt med hjälp av Async och Await (Visual Basic) Visar hur du startar flera uppgifter samtidigt. Async-exempel: Gör flera webbbegäranden parallellt
Async Return Types (Visual Basic) Visar de typer som asynkrona metoder kan returnera och förklarar när varje typ är lämplig.
Kontrollflöde i Async-program (Visual Basic) Spårar i detalj kontrollflödet genom en följd av await-uttryck i ett asynkront program. Async-exempel: Kontrollera flöde i Async-program
Fine-Tuning ditt Async-program (Visual Basic) Visar hur du lägger till följande funktioner i din asynkrona lösning:

- Avbryta en Async-uppgift eller en lista över uppgifter (Visual Basic)
- Avbryt Async-aktiviteter efter en tidsperiod (Visual Basic)
- Avbryt återstående asynkrona uppgifter när en är klar (Visual Basic)
- Starta flera asynkrona uppgifter och bearbeta dem när de har slutförts (Visual Basic)
Async-exempel: Finjustera ditt program
Hantera återinträde i Asyncappar (Visual Basic) Visar hur du hanterar fall där en aktiv asynkron åtgärd startas om medan den körs.
WhenAny: Brygga mellan .NET Framework och Windows Runtime Visar hur du överbryggar mellan aktivitetstyper i .NET Framework och IAsyncOperations i Windows Runtime så att du kan använda WhenAny med en Windows Runtime-metod. Async-exempel: Bryggning mellan .NET och Windows Runtime (AsTask och WhenAny)
Async-annullering: Brygga mellan .NET Framework och Windows Runtime Visar hur du överbryggar mellan aktivitetstyper i .NET Framework och IAsyncOperations i Windows Runtime så att du kan använda CancellationTokenSource med en Windows Runtime-metod. Async-exempel: Överbryggning mellan .NET och Windows Runtime (AsTask & Avbrytande)
Använda Async för filåtkomst (Visual Basic) Listar och demonstrerar fördelarna med att använda async och await för att få åtkomst till filer.
Uppgiftsbaserat asynkront mönster (TAP) Beskriver ett nytt mönster för asynkron i .NET Framework. Mönstret baseras på typerna Task och Task(Of TResult).

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

Se även