Asynchronní programování pomocí Async a Await (Visual Basic)

Pomocí asynchronního programování se můžete vyhnout kritickým bodům a zlepšit celkovou rychlost reakce aplikace. Tradiční techniky pro psaní asynchronních aplikací však mohou být složité, takže je obtížné je napsat, ladit a udržovat.

Visual Studio 2012 zavedl zjednodušený přístup, asynchronní programování, které využívá asynchronní podporu v .NET Framework 4.5 a vyšších a také v prostředí Windows Runtime. Kompilátor na sebe přejímá náročnou práci, kterou vykonával vývojář, a vaše aplikace si zachovává logickou strukturu, která se podobá synchronnímu kódu. Výsledkem je, že získáte všechny výhody asynchronního programování při pouhém zlomku úsilí.

Toto téma obsahuje přehled kdy a jak použít asynchronní programování a obsahuje odkazy na témata podpory, která obsahují podrobné informace a příklady.

Asynchronní funkce zlepšuje rychlost odezvy.

Asynchronie je nezbytná pro aktivity, které mohou potenciálně blokovat, například pokud vaše aplikace přistupuje na web. Přístup k webovému prostředku je někdy pomalý nebo zpožděný. Pokud je taková činnost blokována v rámci synchronního procesu, musí čekat celá aplikace. U asynchronního procesu může aplikace pokračovat v další práci, která nezávisí na webovém prostředku, dokud neskončí potenciálně blokující úloha.

Následující tabulka ukazuje typické oblasti, kde asynchronní programování zlepšuje rychlost reakce. Uvedená rozhraní API z .NET Framework 4.5 a prostředí Windows Runtime obsahují metody, které podporují asynchronní programování.

Oblast aplikace Podpora rozhraní API, která obsahují asynchronní metody
Webový přístup HttpClient, SyndicationClient
Práce se soubory StorageFile, StreamWriter, StreamReader, XmlReader
Práce s obrázky MediaCapture, BitmapEncoder, BitmapDecoder
Programování WCF Synchronní a asynchronní operace

Asynchronie je obzvláště užitečná pro aplikace, které přistupují k vláknu UI, protože všechny aktivity související s uživatelským rozhraním obvykle sdílí jedno vlákno. Pokud je jakýkoli proces blokován v synchronní aplikaci, jsou blokovány všechny. Vaše aplikace přestane reagovat a můžete dojít k závěru, že selhala, i když místo toho čeká.

Při použití asynchronních metod bude aplikace i nadále odpovídat na uživatelské rozhraní. Pokud nechcete čekat na dokončení, můžete změnit velikost nebo minimalizovat okno, například můžete zavřít aplikaci.

Asynchronní přístup přidává ekvivalent automatického přenosu do seznamu možností, z nichž můžete vybírat při vytváření asynchronní operace. To znamená, že získáte všechny výhody tradičního asynchronního programování, ale s mnohem menším úsilím ze strany vývojáře.

Asynchronní metody se snadněji zapisují

Klíčová slova Async a Await v Visual Basic jsou jádrem asynchronního programování. Pomocí těchto dvou klíčových slov můžete pomocí prostředků v .NET Framework nebo prostředí Windows Runtime vytvořit asynchronní metodu téměř stejně snadno jako při vytváření synchronní metody. Asynchronní metody, které definujete pomocí Async a Await jsou označovány jako asynchronní metody.

Následující příklad ukazuje asynchronní metodu. Téměř vše v rámci kódu by vám mělo být zcela známé. Komentáře volají funkce, které jste přidali při tvorbě asynchronie.

Kompletní ukázkový soubor Windows Presentation Foundation (WPF) najdete na konci tohoto tématu a ukázku si můžete stáhnout z asynchronní ukázky: Příklad asynchronního programování pomocí Async a 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

Pokud AccessTheWebAsync nemá žádnou práci, kterou může provádět mezi voláním GetStringAsync a čekáním na dokončení, můžete kód zjednodušit voláním a čekáním v následujícím jediném příkazu.

Dim urlContents As String = Await client.GetStringAsync()

Následující charakteristiky shrnují, co dělá předchozí příklad asynchronní metodou:

  • Podpis metody obsahuje Async modifikátor.

  • Název asynchronní metody končí podle konvence příponou „Async“.

  • Návratový typ je jeden z následujících typů:

    • Task(Of TResult), pokud vaše metoda má návratový příkaz, ve kterém operand má typ TResult.
    • Task pokud vaše metoda nemá žádný návratový příkaz nebo má návratový příkaz bez operandu.
    • Pokud píšete asynchronní obslužnou rutinu události.

    Další informace naleznete v části „Návratové typy a parametry“ dále v tomto tématu.

  • Metoda obvykle zahrnuje nejméně jeden očekávaný výraz, který označuje bod, kde metoda nemůže pokračovat, dokud očekávaná asynchronní operace nebude dokončena. Během této doby je metoda pozastavena a ovládací prvek se vrátí volajícímu metody. Další část tohoto tématu ukazuje, co se stane v okamžiku pozastavení.

V asynchronních metodách používáte zadaná klíčová slova a typy pro označení, jakou akci chcete provést, a kompilátor udělá zbytek, včetně udržování přehledu o tom, co musí nastat, když se řízení vrátí do bodu „await“ pozastavené metody. Některé běžné procesy, jako je zpracování smyček a výjimek, může být v tradičním asynchronním kódu obtížné zpracovat. V asynchronní metodě zapisujete tyto prvky podobně, jako byste to udělali v synchronním řešení, a problém je vyřešen.

Další informace o asynchronii v předchozích verzích .NET Framework naleznete v tématu TPL a Tradiční .NET Framework Asynchronní programování.

Co se stane v asynchronní metodě

Nejdůležitějším principem, který je třeba pochopit v asynchronním programování, je, jak ovládat přesuny toků od metody k metodě. Následující diagram vás provede procesem:

Diagram that shows tracing an async program.

Čísla v diagramu odpovídají následujícím krokům:

  1. Volání obslužné rutiny události a čeká na asynchronní metodu AccessTheWebAsync .

  2. AccessTheWebAsyncHttpClient vytvoří instanci a zavolá asynchronní metoduGetStringAsync, která stáhne obsah webu jako řetězec.

  3. Něco se stane v GetStringAsync tom, že pozastaví jeho průběh. Možná je třeba vyčkat na dokončení stahování nebo jiné blokující aktivity na webu. Aby se zabránilo blokování prostředků, GetStringAsync dává volajícímu kontrolu, AccessTheWebAsync.

    GetStringAsync vrátí Task(Of TResult), kde TResult je řetězec a AccessTheWebAsync přiřadí úkol proměnné getStringTask . Úkol představuje probíhající proces volání GetStringAsync, s závazkem vytvořit skutečnou řetězcovou hodnotu po dokončení práce.

  4. Vzhledem k tomu getStringTask , že ještě nebyl očekáván, může pokračovat v další práci, AccessTheWebAsync která nezávisí na konečném výsledku od GetStringAsync. Tato práce je reprezentována voláním synchronní metody DoIndependentWork.

  5. DoIndependentWork je synchronní metoda, která provádí svou práci a vrací se do volajícího.

  6. AccessTheWebAsync má nedostatek práce, že to může dělat bez výsledku z getStringTask. AccessTheWebAsync Dále chce vypočítat a vrátit délku staženého řetězce, ale metoda nemůže tuto hodnotu vypočítat, dokud metoda nebude mít řetězec.

    AccessTheWebAsync Proto pomocí operátoru await pozastaví svůj průběh a získá kontrolu nad metodou, která se nazývá AccessTheWebAsync. AccessTheWebAsync vrátí volajícímu hodnotu Task(Of Integer) . Úloha představuje slib vyrábět celé číslo výsledku, který má délku staženého řetězce.

    Poznámka

    Je-li GetStringAsync (a proto getStringTask) dokončen před AccessTheWebAsync čekáním, zůstane ovládací prvek v AccessTheWebAsync. Náklady na pozastavení a následné vrácení AccessTheWebAsync by byly plýtvání, pokud se volaný asynchronní proces (getStringTask) už dokončil a AccessTheWebSync nemusí čekat na konečný výsledek.

    Uvnitř volajícího (v tomto případě obslužná rutina události) bude vzor zpracování pokračovat. Volající může udělat jinou práci, která nezávisí na výsledku před AccessTheWebAsync čekáním na tento výsledek nebo volající může okamžitě čekat. Obslužná rutina události čeká AccessTheWebAsyncna a AccessTheWebAsync čeká na GetStringAsync.

  7. GetStringAsync dokončí a vytvoří výsledek řetězce. Výsledek řetězce není vrácen voláním GetStringAsync tak, jak byste mohli očekávat. (Nezapomeňte, že metoda již vrátila úlohu v kroku 3.) Místo toho je výsledek řetězce uložen v úloze, která představuje dokončení metody, getStringTask. Operátor await načte výsledek z getStringTask. Příkaz přiřazení přiřadí načtený výsledek .urlContents

  8. Pokud AccessTheWebAsync má výsledek řetězce, metoda může vypočítat délku řetězce. Pak je také dokončena práce AccessTheWebAsync a obslužná rutina čekající události může pokračovat. V úplném příkladu na konci tématu si můžete potvrdit, že obslužná rutina události načte a vytiskne hodnotu výsledné délky.

Pokud jste v oblasti asynchronního programování nováčky, zvažte rozdíl mezi synchronním a asynchronním chováním. Synchronní metoda je vrácena, jakmile je její práce dokončena (krok 5), ale asynchronní metoda vrátí hodnotu úlohy, když je její práce pozastavena (kroky 3 a 6). Když asynchronní metoda nakonec dokončí svou práci, je úloha označena jako dokončená a výsledek, pokud existuje, je uložen v úloze.

Další informace o toku řízení naleznete v tématu Řízení Flow v asynchronních programech (Visual Basic).

Asynchronní metody rozhraní API

Možná vás zajímá, kde najít metody, jako GetStringAsync je podpora asynchronního programování. .NET Framework 4,5 nebo vyšší obsahuje mnoho členů, se kterými pracují Async a Await. Tyto členy můžete rozpoznat pomocí přípony "Async", která je připojena k názvu člena, a návratovým typem Task nebo Typem úkolu (Of TResult). Třída například obsahuje metody, System.IO.Stream jako CopyToAsyncje , ReadAsynca WriteAsync vedle synchronních metod CopyTo, Reada Write.

Prostředí Windows Runtime obsahuje také mnoho metod, které můžete používat s aplikacemi AsyncAwait Windows a v nich. Další informace a ukázkové metody najdete v tématu Volání asynchronních rozhraní API v jazyce C# nebo Visual Basic, asynchronní programování (prostředí Windows Runtime aplikace) a WhenAny: Přemostění mezi .NET Framework a prostředí Windows Runtime.

Vlákna

Asynchronní metody mají být neblokující operace. Výraz Await v asynchronní metodě neblokuje aktuální vlákno během spuštění očekávané úlohy. Namísto toho se výraz zaregistruje pro zbývající metody jako pokračování a vrátí řízení volajícímu asynchronní metody.

Await Klíčová Async slova a klíčová slova nezpůsobují vytvoření dalších vláken. Asynchronní metody nevyžadují více vláken, protože asynchronní metoda se nespustí na vlastním vlákně. Metoda pracuje na aktuálním kontextu synchronizace a používá čas ve vlákně pouze v případě, že je metoda aktivní. Můžete použít Task.Run k přesunu práce vázané na procesor na vlákno na pozadí, ale vlákno na pozadí nepomůže s procesem, který jen čeká na zpřístupnění výsledků.

Asynchronní přístup při asynchronním programování se doporučuje v téměř každém případě existujících přístupů. Konkrétně je tento přístup lepší než BackgroundWorker u vstupně-výstupních operací, protože kód je jednodušší a nemusíte se hlídat proti rasovým podmínkám. V kombinaci s asynchronním programováním Task.Runje lepší než BackgroundWorker pro operace vázané na procesor, protože asynchronní programování odděluje podrobnosti koordinace spouštění kódu od práce, která Task.Run se přenáší do fondu vláken.

Async a Await

Pokud určíte, že metoda je asynchronní metoda pomocí modifikátoru Async , povolíte následující dvě funkce.

  • Označená asynchronní metoda může použít Await k určení bodů pozastavení. Operátor await sděluje kompilátoru, že s asynchronními metodami nelze za daným bodem pokračovat, dokud nebude dokončen očekávaný asynchronní proces. Během této doby se ovládací prvek vrátí volajícímu asynchronní metody.

    Pozastavení asynchronní metody ve výrazu Await nepředstavuje konec metody a Finally bloky se nespouštějí.

  • Samotná označená asynchronní metoda může být očekávána metodami, které ji volaly.

Asynchronní metoda obvykle obsahuje jeden nebo více výskytů operátoru Await , ale absence Await výrazů nezpůsobuje chybu kompilátoru. Pokud asynchronní metoda nepoužívá Await operátor k označení bodu pozastavení, metoda se provede jako synchronní metoda, a to i přes Async modifikátor. Kompilátor u takových metod zahlásí upozornění.

Async a Await jsou kontextová klíčová slova. Další informace a příklady naleznete v následujících tématech:

Návratové typy a parametry

V .NET Framework programování obvykle asynchronní metoda vrátí Task hodnotu nebo Task(Of TResult). Uvnitř asynchronní metody se operátor použije na úlohu, Await která se vrátí z volání jiné asynchronní metody.

Jako návratový typ zadáte Task(Of TResult), pokud metoda obsahuje příkaz Return , který určuje operand typu TResult.

Jako návratový typ se používá Task , pokud metoda nemá žádný návratový příkaz nebo má návratový příkaz, který nevrací operand.

Následující příklad ukazuje, jak deklarujete a voláte metodu, která vrací Task(Of TResult) nebo :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()

Každá vrácená úloha představuje probíhající práci. Úloha zapouzdřuje informace o stavu asynchronního procesu a posléze buď konečný výsledek z procesu, nebo výjimku, kterou proces vyvolá v případě neúspěchu.

Asynchronní metoda může být také metodou Sub . Tento návratový typ se používá primárně k definování obslužných rutin událostí, kde je vyžadován návratový typ. Asynchronní obslužné rutiny událostí často slouží jako výchozí bod pro asynchronní programy.

Asynchronní metoda, která je procedurou Sub , nelze očekávat a volající nemůže zachytit žádné výjimky, které metoda vyvolá.

Asynchronní metoda nemůže deklarovat parametry ByRef , ale metoda může volat metody, které mají tyto parametry.

Další informace a příklady najdete v tématu Asynchronní návratové typy (Visual Basic). Další informace o tom, jak zachytit výjimky v asynchronních metodách, najdete v tématu Try... Chytit... Nakonec příkaz.

Asynchronní rozhraní API v programování prostředí Windows Runtime mají jeden z následujících návratových typů, které jsou podobné úlohám:

Další informace a příklad najdete v tématu Volání asynchronních rozhraní API v jazyce C# nebo Visual Basic.

Konvence

Podle konvence připojíte "Async" k názvům metod, které mají Async modifikátor.

Můžete ignorovat konvenci, kde událost, základní třída a rozhraní smlouvy navrhují odlišný název. Například byste neměli přejmenovat běžné obslužné rutiny událostí, například Button1_Click.

Související témata a ukázky (Visual Studio)

Nadpis Popis Ukázka
Návod: Přístup k webu pomocí Async a Await (Visual Basic) Ukazuje, jak převést synchronní řešení WPF na asynchronní řešení WPF. Aplikace stáhne řadu webových stránek. Asynchronní ukázka: Asynchronní programování pomocí Async a Await (Visual Basic)
Postupy: Rozšíření návodu async pomocí task.WhenAll (Visual Basic) Přidá Task.WhenAll do předchozího návodu. Použití všech stažených WhenAll souborů současně spustí.
Postupy: Paralelní provádění více webových požadavků pomocí Async a Await (Visual Basic) Ukazuje, jak spustit několik úloh současně. Asynchronní ukázka: Paralelní provádění více webových požadavků
Asynchronní návratové typy (Visual Basic) Znázorňuje typy, které může vrátit asynchronní metoda, a vysvětluje, kdy se každý typ hodí.
Ovládací Flow v asynchronních programech (Visual Basic) Podrobně sleduje tok řízení pomocí sledu očekávání výrazů v asynchronním programu. Asynchronní ukázka: Řízení Flow v asynchronních programech
Vyladění asynchronní aplikace (Visual Basic) Ukazuje, jak přidat k asynchronnímu řešení následující funkce:

- Zrušení asynchronního úkolu nebo seznamu úkolů (Visual Basic)
- Zrušení asynchronních úkolů po uplynutí časového období (Visual Basic)
- Zrušení zbývajících asynchronních úloh po dokončení jedné (Visual Basic)
- Spuštění několika asynchronních úloh a jejich zpracování při jejich dokončení (Visual Basic)
Asynchronní ukázka: Vyladění aplikace
Zpracování opětovného zaentrování v asynchronních aplikacích (Visual Basic) Ukazuje, jak zpracovat případy, ve kterých se při spuštění restartuje aktivní asynchronní operace.
WhenAny: Přemostění mezi .NET Framework a prostředí Windows Runtime Ukazuje, jak přemostit mezi typy úloh v .NET Framework a IAsyncOperations v prostředí Windows Runtime, abyste mohli použít WhenAny s metodou prostředí Windows Runtime. Asynchronní ukázka: Přemostění mezi .NET a prostředí Windows Runtime (AsTask a WhenAny)
Asynchronní zrušení: přemostění rozhraní .NET Framework a prostředí Windows Runtime Ukazuje, jak přemostit mezi typy úloh v .NET Framework a IAsyncOperations v prostředí Windows Runtime, abyste mohli použít CancellationTokenSource s metodou prostředí Windows Runtime. Asynchronní ukázka: Přemostění mezi .NET a prostředí Windows Runtime (zrušení AsTask&)
Použití Async pro přístup k souborům (Visual Basic) Seznam a ukázka výhod použití operátorů async a await při přístupu k souborům.
Asynchronní vzor založený na úlohách (TAP) Popisuje nový vzor pro asynchronii v rozhraní .NET Framework. Model je založený na typech a typech TaskTask(Of TResult ).
Asynchronní videa na kanálu 9 Poskytuje odkazy na různá videa o asynchronním programování.

Kompletní příklad

Následující kód je soubor MainWindow.xaml.vb z aplikace Windows Presentation Foundation (WPF), kterou toto téma popisuje. Ukázku si můžete stáhnout z ukázky Async: Příklad z asynchronního programování pomocí Async a 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

Viz také