Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
U kunt knelpunten in de prestaties voorkomen en de algehele reactiesnelheid van uw toepassing verbeteren met behulp van asynchrone programmering. Traditionele technieken voor het schrijven van asynchrone toepassingen kunnen echter ingewikkeld zijn, waardoor ze moeilijk kunnen worden geschreven, fouten kunnen worden opgespoord en onderhouden.
C# biedt ondersteuning voor vereenvoudigde benadering, asynchrone programmering, die gebruikmaakt van asynchrone ondersteuning in de .NET-runtime. De compiler doet het moeilijke werk dat de ontwikkelaar heeft gebruikt en uw toepassing behoudt een logische structuur die lijkt op synchrone code. Als gevolg hiervan krijgt u alle voordelen van asynchrone programmering met een fractie van de inspanning.
Dit onderwerp bevat een overzicht van wanneer en hoe u asynchrone programmering gebruikt en koppelingen bevat naar ondersteuningsonderwerpen die details en voorbeelden bevatten.
Async verbetert de reactiesnelheid
Asynchroon is essentieel voor activiteiten die mogelijk blokkeren, zoals webtoegang. De toegang tot een webresource is soms traag of vertraagd. Als een dergelijke activiteit wordt geblokkeerd in een synchroon proces, moet de hele toepassing wachten. In een asynchroon proces kan de toepassing doorgaan met ander werk dat niet afhankelijk is van de webresource totdat de potentieel blokkerende taak is voltooid.
In de volgende tabel ziet u typische gebieden waarin asynchrone programmering de reactiesnelheid verbetert. De vermelde API's van .NET en Windows Runtime bevatten methoden die ondersteuning bieden voor asynchrone programmering.
Toepassingsgebied | .NET-typen met asynchrone methoden | Typen Windows Runtime met asynchrone methoden |
---|---|---|
Webtoegang | HttpClient | Windows.Web.Http.HttpClient SyndicationClient |
Werken met bestanden | JsonSerializer StreamReader StreamWriter XmlReader XmlWriter |
StorageFile |
Werken met afbeeldingen | MediaCapture BitmapEncoder BitmapDecoder |
|
WCF-programmering | Synchrone en Asynchrone Bewerkingen |
Asynchrony bewijst met name waardevol voor toepassingen die toegang hebben tot de UI-thread, omdat alle ui-gerelateerde activiteiten meestal één thread delen. Als een proces wordt geblokkeerd in een synchrone toepassing, worden alle processen geblokkeerd. Uw toepassing reageert niet meer en u kunt concluderen dat deze is mislukt wanneer de toepassing gewoon wacht.
Wanneer u asynchrone methoden gebruikt, blijft de toepassing reageren op de gebruikersinterface. U kunt bijvoorbeeld het formaat van een venster wijzigen of minimaliseren, of u kunt de toepassing sluiten als u niet wilt wachten totdat het is voltooid.
De asynchrone benadering voegt het equivalent van een automatische overdracht toe aan de lijst met opties waaruit u kunt kiezen bij het ontwerpen van asynchrone bewerkingen. Dat wil gezegd, u krijgt alle voordelen van traditionele asynchrone programmering, maar met veel minder inspanning van de ontwikkelaar.
Asynchrone methoden zijn eenvoudig te schrijven
De async en await trefwoorden in C# vormen het hart van asynchrone programmering. Met deze twee trefwoorden kunt u resources in .NET Framework, .NET Core of Windows Runtime gebruiken om bijna net zo eenvoudig een asynchrone methode te maken als u een synchrone methode maakt. Asynchrone methoden die u definieert met behulp van het async
trefwoord, worden asynchrone methoden genoemd.
In het volgende voorbeeld ziet u een asynchrone methode. Bijna alles in de code moet er bekend uitzien.
U kunt een compleet voorbeeld van de Windows Presentation Foundation (WPF) downloaden van Asynchrone programmering met async en await in 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...");
}
U kunt verschillende procedures uit het voorgaande voorbeeld leren. Begin met de methode-signatuur. Het bevat de async
wijzigingsfunctie. Het retourtype is Task<int>
(zie de sectie Retourtypen voor meer opties). De methodenaam eindigt in Async
. In de hoofdtekst van de methode retourneert GetStringAsync
een Task<string>
. Dat betekent dat wanneer u await
de taak, u een string
krijgt (contents
). Voordat u op de taak wacht, kunt u werk uitvoeren dat niet afhankelijk is van de string
van GetStringAsync
.
Let goed op de await
-operator. Het schort GetUrlContentLengthAsync
op:
-
GetUrlContentLengthAsync
kan niet doorgaan totdatgetStringTask
is voltooid. - Ondertussen keert de besturing terug naar de aanroeper van
GetUrlContentLengthAsync
. - Hier wordt de controle hervat wanneer
getStringTask
is voltooid. - De
await
operator haalt vervolgens hetstring
resultaat op vangetStringTask
.
De retourinstructie specificeert een geheel getal als resultaat. Alle methoden die wachten GetUrlContentLengthAsync
op het ophalen van de lengtewaarde.
Als GetUrlContentLengthAsync
geen werk heeft dat het kan doen tussen het aanroepen van GetStringAsync
en het wachten op de voltooiing ervan, kunt u uw code vereenvoudigen door deze in één enkele instructie aan te roepen en te wachten.
string contents = await client.GetStringAsync("https://learn.microsoft.com/dotnet");
De volgende kenmerken geven een overzicht van wat het vorige voorbeeld een asynchrone methode maakt:
De methodehandtekening bevat een
async
modifier.De naam van een asynchrone methode eindigt op conventie met een Async-achtervoegsel.
Het retourtype is een van de volgende typen:
-
Task<TResult> als uw methode een retourinstructie heeft waarin de operand type
TResult
heeft. - Task als uw methode geen retourinstructie heeft of een retourinstructie zonder operand heeft.
-
void
wanneer u een asynchrone gebeurtenisbeheerder schrijft. - Elk ander type dat een
GetAwaiter
methode heeft.
Zie de sectie Retourtypen en parameters voor meer informatie.
-
Task<TResult> als uw methode een retourinstructie heeft waarin de operand type
De methode bevat meestal ten minste één
await
expressie, waarmee een punt wordt gemarkeerd waarop de methode niet kan worden voortgezet totdat de wachtende asynchrone bewerking is voltooid. Ondertussen wordt de methode gepauzeerd, en gaat de controle terug naar de aanroeper van de methode. In de volgende sectie van dit onderwerp ziet u wat er op het schorsingspunt gebeurt.
In asynchrone methoden gebruikt u de opgegeven trefwoorden en typen om aan te geven wat u wilt doen, en de compiler doet de rest, inclusief het bijhouden van wat er moet gebeuren wanneer het besturingselement terugkeert naar een wachtpunt in een onderbroken methode. Sommige routineprocessen, zoals lussen en afhandeling van uitzonderingen, kunnen moeilijk te verwerken zijn in traditionele asynchrone code. In een asynchrone methode schrijft u deze elementen net zoals in een synchrone oplossing en wordt het probleem opgelost.
Zie TPL en traditionele .NET Framework asynchrone programmering voor meer informatie over asynchroon programmeren in eerdere versies van .NET Framework.
Wat gebeurt er in een asynchrone methode?
Het belangrijkste om te begrijpen in asynchrone programmering is hoe de controlestroom van methode naar methode wordt verplaatst. Het volgende diagram leidt u door het proces:
De getallen in het diagram komen overeen met de volgende stappen, geïnitieerd wanneer een aanroepmethode de asynchrone methode aanroept.
Een aanroepmethode roept en wacht op de
GetUrlContentLengthAsync
asynchrone methode.GetUrlContentLengthAsync
maakt een HttpClient exemplaar en roept de GetStringAsync asynchrone methode aan om de inhoud van een website als een tekenreeks te downloaden.Er gebeurt iets in
GetStringAsync
dat de voortgang ervan onderbreekt. Misschien moet er worden gewacht totdat een website is gedownload of een andere blokkeringsactiviteit. Om te voorkomen dat resources worden geblokkeerd,GetStringAsync
levert dit de controle over de aanroeperGetUrlContentLengthAsync
op.GetStringAsync
retourneert een Task<TResult>, waarbijTResult
een tekenreeks is enGetUrlContentLengthAsync
wijst de taak toe aan degetStringTask
variabele. De taak vertegenwoordigt het doorlopende proces voor de aanroep naarGetStringAsync
, met een toezegging om een werkelijke tekenreekswaarde te produceren wanneer het werk is voltooid.Omdat
getStringTask
nog niet is afgewacht, kanGetUrlContentLengthAsync
doorgaan met ander werk dat niet afhankelijk is van het uiteindelijke resultaat vanGetStringAsync
. Dat werk wordt vertegenwoordigd door een aanroep naar de synchrone methodeDoIndependentWork
.DoIndependentWork
is een synchrone methode die het werk uitvoert en terugkeert naar de aanroeper.GetUrlContentLengthAsync
heeft geen werk meer om te doen zonder een resultaat vangetStringTask
.GetUrlContentLengthAsync
vervolgens wil de lengte van de gedownloade tekenreeks berekenen en retourneren, maar de methode kan die waarde pas berekenen als de methode de tekenreeks heeft.Daarom gebruikt
GetUrlContentLengthAsync
een wachtoperator om zijn voortgang op te schorten en de controle over te dragen aan de methode dieGetUrlContentLengthAsync
heeft aangeroepen.GetUrlContentLengthAsync
retourneert eenTask<int>
aan de aanroeper. De taak stelt een belofte voor om een geheel getal te produceren dat overeenkomt met de lengte van de gedownloade tekenreeks.Opmerking
Als
GetStringAsync
(en dusgetStringTask
) voltooit voordatGetUrlContentLengthAsync
het verwacht, blijft de controle inGetUrlContentLengthAsync
. De kosten van het opschorten en vervolgens hervatten naarGetUrlContentLengthAsync
worden verspild als het aangeroepen asynchrone procesgetStringTask
al is voltooid enGetUrlContentLengthAsync
niet hoeft te wachten op het uiteindelijke resultaat.Binnen de aanroepende methode wordt het verwerkingspatroon voortgezet. De beller kan ander werk doen dat niet afhankelijk is van het resultaat van
GetUrlContentLengthAsync
voordat hij dat resultaat wacht, of de beller kan onmiddellijk wachten. De aanroepmethode wacht opGetUrlContentLengthAsync
enGetUrlContentLengthAsync
wacht opGetStringAsync
.GetStringAsync
voltooit en produceert een tekenreeksresultaat. Het resultaat van de tekenreeks wordt niet op de manier die u zou verwachten geretourneerd door de aanroep naarGetStringAsync
. (Houd er rekening mee dat de methode al een taak heeft geretourneerd in stap 3.) In plaats daarvan wordt het tekenreeksresultaat opgeslagen in de taak die de voltooiing van de methode aangeeft.getStringTask
De wachtoperator haalt het resultaat op vangetStringTask
. Met de toewijzingsinstructie wordt het opgehaalde resultaat toegewezen aancontents
.Wanneer
GetUrlContentLengthAsync
het tekenreeksresultaat is, kan de methode de lengte van de tekenreeks berekenen. Zodra het werk vanGetUrlContentLengthAsync
voltooid is, kan de wachtende eventhandler hervatten. In het volledige voorbeeld aan het einde van het onderwerp kunt u bevestigen dat de gebeurtenis-handler de waarde van het lengteresultaat ophaalt en afdrukt. Neem even de tijd om na te denken over het verschil tussen synchroon en asynchroon gedrag als u nieuw bent in asynchrone programmering. Een synchrone methode retourneert wanneer het werk is voltooid (stap 5), maar een asynchrone methode retourneert een taakwaarde wanneer het werk wordt onderbroken (stap 3 en 6). Wanneer de asynchrone methode uiteindelijk het werk voltooit, wordt de taak gemarkeerd als voltooid en wordt het resultaat, indien aanwezig, opgeslagen in de taak.
Asynchrone API-methoden
Mogelijk vraagt u zich af waar u methoden kunt vinden, zoals GetStringAsync
die ondersteuning bieden voor asynchrone programmering. .NET Framework 4.5 of hoger en .NET Core bevatten veel leden die werken met async
en await
. U kunt deze herkennen door het achtervoegsel 'Async' dat aan de lidnaam wordt toegevoegd en aan hun retourtype van Task of Task<TResult>. De System.IO.Stream
klasse bevat bijvoorbeeld methoden zoals CopyToAsync, ReadAsyncen WriteAsync naast de synchrone methoden CopyTo, Readen Write.
De Windows Runtime bevat ook veel methoden die u kunt gebruiken met async
en await
in Windows-apps. Zie Threading en asynchrone programmering voor UWP-ontwikkeling en Asynchrone programmering (Windows Store-apps) en quickstart: asynchrone API's aanroepen in C# of Visual Basic als u eerdere versies van Windows Runtime gebruikt.
Draden
Asynchrone methoden zijn bedoeld als niet-blokkerende bewerkingen. Een await
expressie in een asynchrone methode blokkeert de huidige thread niet terwijl de wachtende taak wordt uitgevoerd. In plaats daarvan registreert de expressie de rest van de methode als vervolg en retourneert het besturingselement naar de aanroeper van de asynchrone methode.
De async
trefwoorden en await
trefwoorden zorgen ervoor dat er geen extra threads worden gemaakt. Asynchrone methoden vereisen geen multithreading omdat een asynchrone methode niet wordt uitgevoerd op een eigen thread. De methode wordt uitgevoerd op de huidige synchronisatiecontext en gebruikt alleen tijd op de thread wanneer de methode actief is. U kunt Task.Run cpu-gebonden werk verplaatsen naar een achtergrondthread, maar een achtergrondthread helpt niet bij een proces dat alleen wacht tot er resultaten beschikbaar zijn.
De asynchrone benadering van programmeeractiviteiten is in bijna elk geval te verkiezen boven de bestaande benaderingen. Deze benadering is met name beter dan de BackgroundWorker klasse voor I/O-gebonden bewerkingen, omdat de code eenvoudiger is en u niet hoeft te beschermen tegen racevoorwaarden. In combinatie met de Task.Run methode is asynchroon programmeren beter dan BackgroundWorker voor CPU-afhankelijke bewerkingen, omdat asynchrone programmering de coördinatiedetails van het uitvoeren van uw code scheidt van het werk dat Task.Run
wordt overgedragen naar de threadpool.
asynchroon en wachten
Als u opgeeft dat een methode een asynchrone methode is met behulp van de asynchrone wijziging, schakelt u de volgende twee mogelijkheden in.
De gemarkeerde async-methode kan await gebruiken om ophangpunten aan te wijzen. De
await
operator vertelt de compiler dat de asynchrone methode niet verder kan gaan dan dat punt totdat het wachtende asynchrone proces is voltooid. In de tussentijd keert de controle terug naar de aanroeper van de asynchrone methode.De schorsing van een asynchrone methode bij een
await
expressie vormt geen exit van de methode enfinally
blokken worden niet uitgevoerd.De gemarkeerde asynchrone methode kan zelf worden afgewacht door methodes die deze aanroepen.
Een asynchrone methode bevat doorgaans een of meer exemplaren van een await
operator, maar het ontbreken van await
expressies veroorzaakt geen compilerfout. Als een asynchrone methode geen operator gebruikt await
om een veringspunt te markeren, wordt de methode uitgevoerd als een synchrone methode, ondanks de async
wijzigingsfunctie. De compiler geeft een waarschuwing voor dergelijke methoden uit.
async
en await
zijn contextuele trefwoorden. Zie de volgende onderwerpen voor meer informatie en voorbeelden:
Retourtypen en parameters
Een asynchrone methode retourneert meestal een Task of een Task<TResult>. Binnen een asynchrone methode wordt een await
operator toegepast op een taak die wordt geretourneerd vanuit een aanroep naar een andere asynchrone methode.
U geeft Task<TResult> op als het retourtype als de methode een return
instructie bevat waarmee een operand van het type TResult
wordt opgegeven.
U gebruikt Task als retourtype als de methode geen retourinstructie heeft of een retourinstructie heeft die geen operand retourneert.
U kunt ook elk ander retourtype opgeven, mits het type een GetAwaiter
methode bevat.
ValueTask<TResult> is een voorbeeld van een dergelijk type. Het is beschikbaar in het NuGet-pakket System.Threading.Tasks.Extension .
In het volgende voorbeeld ziet u hoe u een methode declareert en aanroept die een Task<TResult> of een Task retourneert.
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();
Elke geretourneerde taak vertegenwoordigt doorlopend werk. Een taak bevat informatie over de status van het asynchrone proces en uiteindelijk het uiteindelijke resultaat van het proces of de uitzondering die het proces genereert als het niet lukt.
Een asynchrone methode kan ook een void
retourtype hebben. Dit retourtype wordt voornamelijk gebruikt om gebeurtenis-handlers te definiëren, waarbij een void
retourtype vereist is. Asynchrone gebeurtenishandlers dienen vaak als uitgangspunt voor asynchrone programma's.
Een asynchrone methode met een void
retourtype kan niet worden afgewacht, en de aanroeper van een methode die void retourneert, kan geen exceptions opvangen die de methode genereert.
Een asynchrone methode kan geen in-, ref- of out-parameters declareren, maar de methode kan wel andere methoden aanroepen die dergelijke parameters hebben. Op dezelfde manier kan een asynchrone methode een waarde niet per verwijzing retourneren, hoewel deze methoden kan aanroepen met ref-retourwaarden.
Zie Asynchrone retourtypen (C#) voor meer informatie en voorbeelden.
Asynchrone API's in Windows Runtime-programmering hebben een van de volgende retourtypen, die vergelijkbaar zijn met taken:
- IAsyncOperation<TResult>, dat overeenkomt met Task<TResult>
- IAsyncAction, dat overeenkomt met Task
- IAsyncActionWithProgress<TProgress>
- IAsyncOperationWithProgress<TResult,TProgress>
Naamgevingsconventie
Volgens de conventie moeten methoden die vaak te verwachten typen retourneren (bijvoorbeeld Task
, Task<T>
ValueTask
, ValueTask<T>
) namen hebben die eindigen op 'Async'. Methoden die een asynchrone bewerking starten, maar geen verwachtbaar type retourneren, mogen geen namen hebben die eindigen op 'Async', maar kunnen beginnen met 'Begin', 'Start' of een ander werkwoord om aan te geven dat deze methode niet retourneert of het resultaat van de bewerking genereert.
U kunt de conventie negeren waarbij een gebeurtenis, basisklasse of interfacecontract een andere naam voorstelt. U moet bijvoorbeeld de naam van algemene gebeurtenishandlers niet wijzigen, zoals OnButtonClick
.
Verwante artikelen (Visual Studio)
Titel | Beschrijving |
---|---|
Meerdere webaanvragen parallel maken met behulp van asynchroon en wachten (C#) | Demonstreert hoe u meerdere taken tegelijk start. |
Asynchrone retourtypen (C#) | Illustreert de typen die asynchrone methoden kunnen retourneren en legt uit wanneer elk type geschikt is. |
Annuleer taken met een annuleringstoken als signaleringsmechanisme. | Laat zien hoe u de volgende functionaliteit toevoegt aan uw asynchrone oplossing: - Een lijst met taken annuleren (C#) - Taken annuleren na een bepaalde periode (C#) - Verwerk de asynchrone taken wanneer deze zijn voltooid (C#) |
Asynchroon gebruiken voor bestandstoegang (C#) | Laat de voordelen zien van het gebruik van async en await voor toegang tot bestanden. |
Taak-gebaseerd asynchroon patroon (TAP) | Beschrijft een asynchroon patroon, het patroon is gebaseerd op de Task en Task<TResult> typen. |
Async Video's op Channel 9 | Biedt koppelingen naar verschillende video's over asynchrone programmering. |