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:
Čísla v diagramu odpovídají následujícím krokům:
Volání obslužné rutiny události a čeká na asynchronní metodu
AccessTheWebAsync
.AccessTheWebAsync
HttpClient vytvoří instanci a zavolá asynchronní metoduGetStringAsync, která stáhne obsah webu jako řetězec.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 aAccessTheWebAsync
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.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 odGetStringAsync
. Tato práce je reprezentována voláním synchronní metodyDoIndependentWork
.DoIndependentWork
je synchronní metoda, která provádí svou práci a vrací se do volajícího.AccessTheWebAsync
má nedostatek práce, že to může dělat bez výsledku zgetStringTask
.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 hodnotuTask(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 protogetStringTask
) dokončen předAccessTheWebAsync
čekáním, zůstane ovládací prvek vAccessTheWebAsync
. 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áAccessTheWebAsync
na aAccessTheWebAsync
čeká naGetStringAsync
.GetStringAsync
dokončí a vytvoří výsledek řetězce. Výsledek řetězce není vrácen volánímGetStringAsync
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 zgetStringTask
. Příkaz přiřazení přiřadí načtený výsledek .urlContents
Pokud
AccessTheWebAsync
má výsledek řetězce, metoda může vypočítat délku řetězce. Pak je také dokončena práceAccessTheWebAsync
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 Async
Await
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 aFinally
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:
- IAsyncOperation(Of TResult), která odpovídá úkolu(Of TResult)
- IAsyncAction, který odpovídá Task
- IAsyncActionWithProgress(Of TProgress)
- IAsyncOperationWithProgress(Of TResult, TProgress)
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)
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