Model asynchronního programování úloh
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.
Jazyk C# podporuje zjednodušený přístup, asynchronní programování, které využívá asynchronní podporu v modulu runtime .NET. 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.
Asynchronní synchronizace je nezbytná pro aktivity, které mohou blokovat, například webový přístup. Přístup k webovému prostředku je někdy pomalý nebo zpožděný. Pokud je taková aktivita zablokovaná v synchronním procesu, musí celá aplikace počkat. 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 a prostředí Windows Runtime obsahují metody, které podporují asynchronní programování.
Oblast aplikace | Typy .NET s asynchronními metodami | prostředí Windows Runtime typy pomocí asynchronních metod |
---|---|---|
Webový přístup | HttpClient | Windows.Web.Http.HttpClient SyndicationClient |
Práce se soubory | JsonSerializer StreamReader StreamWriter XmlReader XmlWriter |
StorageFile |
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 snadno zapisují
Asynchronní a očekávaná klíčová slova v jazyce C# jsou jádrem asynchronního programování. Pomocí těchto dvou klíčových slov můžete použít prostředky v rozhraní .NET Framework, .NET Core nebo prostředí Windows Runtime k vytvoření asynchronní metody téměř stejně snadno jako při vytváření synchronní metody. Asynchronní metody, které definujete pomocí klíčového async
slova, se označují jako asynchronní metody.
Následující příklad ukazuje asynchronní metodu. Téměř všechno v kódu by mělo vypadat dobře.
Kompletní příklad Windows Presentation Foundation (WPF) je k dispozici ke stažení z asynchronního programování s asynchronním programováním a v jazyce C#.
public async Task<int> GetUrlContentLengthAsync()
{
using var client = new HttpClient();
Task<string> getStringTask =
client.GetStringAsync("https://learn.microsoft.com/dotnet");
DoIndependentWork();
string contents = await getStringTask;
return contents.Length;
}
void DoIndependentWork()
{
Console.WriteLine("Working...");
}
Z předchozí ukázky se můžete seznámit s několika postupy. Začněte podpisem metody. async
Obsahuje modifikátor. Návratový typ je Task<int>
(další možnosti najdete v části Návratové typy). Název metody končí .Async
V těle metody GetStringAsync
vrátí hodnotu Task<string>
. To znamená, že když úkol dostanete await
string
(contents
). Před čekáním na úkol můžete udělat práci, která nespoléhá na danou GetStringAsync
možnost string
.
Věnujte operátoru await
velkou pozornost. Pozastaví GetUrlContentLengthAsync
se:
GetUrlContentLengthAsync
nemůže pokračovat, dokudgetStringTask
nebude dokončen.- Mezitím se ovládací prvek vrátí volajícímu
GetUrlContentLengthAsync
. - Jakmile bude dokončený, ovládací prvek se tady
getStringTask
obnoví. - Operátor
await
pak načtestring
výsledek zgetStringTask
.
Příkaz return určuje celočíselnou výsledek. Všechny metody čekající na GetUrlContentLengthAsync
načtení hodnoty délky.
Pokud GetUrlContentLengthAsync
nemá žádnou práci, kterou může provést 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.
string contents = await client.GetStringAsync("https://learn.microsoft.com/dotnet");
Následující charakteristiky shrnují, co dělá z předchozího příkladu asynchronní metodu:
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<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.
void
pokud píšete asynchronní obslužnou rutinu události.- Jakýkoli jiný typ, který má metodu
GetAwaiter
.
Další informace najdete v části Návratové typy a parametry .
- Task<TResult> pokud vaše metoda má návratový příkaz, ve kterém operand má typ
Metoda obvykle obsahuje alespoň jeden
await
výraz, který označuje bod, kdy metoda nemůže pokračovat, dokud není dokončena očekávaná asynchronní operace. 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 rozhraní .NET Framework naleznete v tématu TPL a tradiční asynchronní programování rozhraní .NET Framework.
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 zahájeným při volání metody volání asynchronní metody.
Volání metody volá a čeká asynchronní metodu
GetUrlContentLengthAsync
.GetUrlContentLengthAsync
HttpClient vytvoří instanci a zavolá asynchronní metodu GetStringAsync pro stažení obsahu 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á řízení volajícímu ,GetUrlContentLengthAsync
.GetStringAsync
vrátí hodnotu Task<TResult>, kdeTResult
je řetězec aGetUrlContentLengthAsync
přiřadí úkol proměnnégetStringTask
. Úkol představuje probíhající proces voláníGetStringAsync
, se 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,GetUrlContentLengthAsync
může pokračovat v další práci, která nezávisí na konečném výsledku zGetStringAsync
. 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.GetUrlContentLengthAsync
má nedostatek práce, že to může dělat bez výsledku zgetStringTask
.GetUrlContentLengthAsync
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.GetUrlContentLengthAsync
Proto pomocí operátoru await pozastaví svůj průběh a získá kontrolu nad metodou, která volalaGetUrlContentLengthAsync
.GetUrlContentLengthAsync
vrátí volajícímu hodnotuTask<int>
. Úloha představuje slib vyrábět celé číslo výsledku, který má délku staženého řetězce.Poznámka:
Pokud
GetStringAsync
se (a protogetStringTask
) dokončí před tím, nežGetUrlContentLengthAsync
ho čeká, zůstane ovládací prvek vGetUrlContentLengthAsync
. Náklady na pozastavení a následné vráceníGetUrlContentLengthAsync
by byly plýtvání, pokud se volaný asynchronní procesgetStringTask
již dokončil aGetUrlContentLengthAsync
nemusí čekat na konečný výsledek.Uvnitř volající metody pokračuje vzor zpracování. Volající může udělat jinou práci, která nezávisí na výsledku před
GetUrlContentLengthAsync
čekáním na tento výsledek, nebo volající může okamžitě čekat. Volající metoda čeká naGetUrlContentLengthAsync
aGetUrlContentLengthAsync
č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ýsledekcontents
.Pokud
GetUrlContentLengthAsync
má výsledek řetězce, metoda může vypočítat délku řetězce.GetUrlContentLengthAsync
Práce je také dokončena 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.
Asynchronní metody rozhraní API
Možná vás zajímá, kde najít metody, jako GetStringAsync
je například podpora asynchronního programování. .NET Framework 4.5 nebo novější a .NET Core obsahují mnoho členů, se async
kterými pracují a await
. Můžete je rozpoznat podle přípony "Async", která je připojena k názvu člena, a jejich návratovým Task typem nebo Task<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
pro Windows a await
v nich. Další informace najdete v tématu Vytváření vláken a asynchronní programování pro vývoj pro UPW a asynchronní programování (aplikace pro Windows Store) a rychlý start: Volání asynchronních rozhraní API v jazyce C# nebo Visual Basic, pokud používáte starší verze 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, zatímco je spuštěna očekávaná úloha. 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ůsobí vytvoření dalších vláken. Asynchronní metody nevyžadují multithreading, protože asynchronní metoda není spuštěna ve 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řesunutí 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 třída pro vstupně-výstupní operace, protože kód je jednodušší a nemusíte se chránit před podmínkami časování. V kombinaci s metodou Task.Run je asynchronní programování lepší než BackgroundWorker u operací vázaných na procesor, protože asynchronní programování odděluje podrobnosti koordinace spouštění kódu od práce, která Task.Run
přenese 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 funkci await k určení bodů pozastavení. Operátor
await
říká kompilátoru, že asynchronní metoda nemůže pokračovat až do dokončení očekávaného asynchronního procesu. 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 nespustí.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ů await
operátoru, ale absence await
výrazů nezpůsobí chybu kompilátoru. Pokud asynchronní metoda nepoužívá await
operátor k označení bodu pozastavení, metoda se provede jako synchronní metoda 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
Asynchronní metoda obvykle vrací Task nebo Task<TResult>. Uvnitř asynchronní metody await
se operátor použije na úlohu vrácenou z volání jiné asynchronní metody.
Jako návratový typ zadáte Task<TResult> , pokud metoda obsahuje return
příkaz, 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.
Můžete také zadat jakýkoli jiný návratový typ za předpokladu, že typ obsahuje metodu GetAwaiter
. ValueTask<TResult> je příkladem takového typu. Je k dispozici v balíčku NuGet System.Threading.Tasks.Extension .
Následující příklad ukazuje, jak deklarujete a voláte metodu, která vrací Task<TResult> nebo a Task:
async Task<int> GetTaskOfTResultAsync()
{
int hours = 0;
await Task.Delay(0);
return hours;
}
Task<int> returnedTaskTResult = GetTaskOfTResultAsync();
int intResult = await returnedTaskTResult;
// Single line
// int intResult = await GetTaskOfTResultAsync();
async Task GetTaskAsync()
{
await Task.Delay(0);
// No return statement needed
}
Task returnedTask = GetTaskAsync();
await returnedTask;
// Single line
await GetTaskAsync();
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 mít také návratový void
typ. Tento návratový typ se používá především k definování obslužných rutin událostí, kde je vyžadován návratový void
typ. Asynchronní obslužné rutiny událostí často slouží jako výchozí bod pro asynchronní programy.
Asynchronní metoda, která má návratový void
typ, nelze očekávat a volající metody void-returning nemůže zachytit žádné výjimky, které metoda vyvolá.
Asynchronní metoda nemůže deklarovat parametry ref nebo out, ale metoda může volat metody, které mají tyto parametry. Podobně asynchronní metoda nemůže vrátit hodnotu podle odkazu, i když může volat metody s návratovými hodnotami ref.
Další informace a příklady najdete v tématu Asynchronní návratové typy (C#).
Asynchronní rozhraní API v prostředí Windows Runtime programování mají jeden z následujících návratových typů, které se podobají úlohám:
- IAsyncOperation<TResult>, který odpovídá Task<TResult>
- IAsyncAction, který odpovídá Task
- IAsyncActionWithProgress<TProgress>
- IAsyncOperationWithProgress<TResult,TProgress>
Konvence pojmenování
Podle konvence by metody, které vracejí běžně očekávané typy (například Task
, Task<T>
, ValueTask
, ValueTask<T>
) měly mít názvy, které končí na "Async". Metody, které spouští asynchronní operaci, ale nevrací očekávaný typ, by neměly mít názvy, které končí na "Async", ale mohou začínat na "Begin", "Start" nebo nějaký jiný příkaz navrhnout tuto metodu nevrací nebo vyvolá výsledek operace.
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 OnButtonClick
.
Související články (Visual Studio)
Titulek | Popis |
---|---|
Paralelní provádění více webových požadavků pomocí asynchronního volání a operátoru await (C#) | Ukazuje, jak spustit několik úloh současně. |
Asynchronní návratové typy (C#) | Znázorňuje typy, které asynchronní metody mohou vrátit, a vysvětluje, kdy je každý typ vhodný. |
Zrušení úloh pomocí tokenu zrušení jako signalizačního mechanismu | Ukazuje, jak přidat k asynchronnímu řešení následující funkce: - Zrušení seznamu úkolů (C#) - Zrušení úkolů po určité době (C#) - Zpracování asynchronní úlohy při jejich dokončení (C#) |
Použití async pro přístup k souborům (C#) | 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 asynchronní vzor, vzor je založený na typech a Task<TResult> typechTask. |
Asynchronní videa na channel 9 | Poskytuje odkazy na různá videa o asynchronním programování. |