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:

Diagram that shows tracing an async program.

Siffrorna i diagrammet motsvarar följande steg:

  1. En händelsehanterare anropar och väntar på AccessTheWebAsync metoden async.

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

    GetStringAsync returnerar en Task(Of 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äntat ä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 slut på arbete som det kan gö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.

    AccessTheWebAsync Därför använder en await-operator för att pausa förloppet och för att ge kontroll till metoden som anropade AccessTheWebAsync. AccessTheWebAsync returnerar en Task(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ör getStringTask) har slutförts innan AccessTheWebAsync det väntar, finns kontrollen kvar i AccessTheWebAsync. Kostnaden för att pausa och sedan återgå till AccessTheWebAsync 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å AccessTheWebAsyncoch AccessTheWebAsync väntar på GetStringAsync.

  7. GetStringAsync slutförs och skapar 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 AccessTheWebAsync 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 och Finally 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:

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)

Rubrik 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)
Anvisningar: 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.
Anvisningar: 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) Illustrerar de typer som asynkrona metoder kan returnera och förklarar när varje typ är lämplig.
Kontrollera Flow 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 Flow i Async-program
Finjustera 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 aktiviteter (Visual Basic)
- Avbryt Async-aktiviteter efter en tidsperiod (Visual Basic)
- Avbryt återstående Async-uppgifter när en är klar (Visual Basic)
- Starta flera Async-uppgifter och bearbeta dem när de slutförs (Visual Basic)
Async-exempel: Finjustera ditt program
Hantera återaktivering i Async Apps (Visual Basic) Visar hur du hanterar fall där en aktiv asynkron åtgärd startas om medan den körs.
WhenAny: Bryggning 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 Cancellation: Bryggning 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: Bryggning mellan .NET och Windows Runtime (AsTask-annullering&)
Använda Async för Filåtkomst (Visual Basic) Listar och visar fördelarna med att använda async och väntar på 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 TaskTask (Of TResult) och Task(Of TResult).
Async-videor på Channel 9 Innehåller länkar till en mängd olika videor om asynkron programmering.

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

Se även