Operator „await“: asynchron warten, bis eine Aufgabe abgeschlossen ist
Der Operator await
hält die Auswertung der einschließenden async-Methode an, bis der asynchrone Vorgang abgeschlossen ist, der durch seinen Operanden dargestellt wird. Sobald der asynchrone Vorgang abgeschlossen ist, gibt der Operator await
ggf. das Ergebnis des Vorgangs zurück. Wenn der Operator await
auf den Operanden angewendet wird, der einen bereits abgeschlossenen Vorgang darstellt, wird das Ergebnis des Vorgangs sofort zurückgegeben, ohne dass die einschließende Methode angehalten wird. Der Operator await
blockiert nicht den Thread, der die Async-Methode auswertet. Wenn der Operator await
die einschließende asynchrone Methode anhält, wird das Steuerelement an den Aufrufer der Methode zurückgegeben.
Im folgenden Beispiel gibt die Methode HttpClient.GetByteArrayAsync die Instanz Task<byte[]>
zurück, die einen asynchronen Vorgang darstellt, der ein Bytearray erzeugt, wenn er abgeschlossen wird. Der Operator await
hält so lange die Methode DownloadDocsMainPageAsync
an, bis der Vorgang abgeschlossen ist. Wenn DownloadDocsMainPageAsync
angehalten wird, wird die Steuerung an die Methode Main
zurückgegeben. Bei dieser handelt es sich um den Aufrufer von DownloadDocsMainPageAsync
. Die Methode Main
wird so lange ausgeführt, bis sie das Ergebnis des asynchronen Vorgangs benötigt, der von der Methode DownloadDocsMainPageAsync
ausgeführt wird. Wenn GetByteArrayAsync alle Bytes abruft, wird der Rest der Methode DownloadDocsMainPageAsync
ausgewertet. Danach wird der Rest der Methode Main
ausgewertet.
public class AwaitOperator
{
public static async Task Main()
{
Task<int> downloading = DownloadDocsMainPageAsync();
Console.WriteLine($"{nameof(Main)}: Launched downloading.");
int bytesLoaded = await downloading;
Console.WriteLine($"{nameof(Main)}: Downloaded {bytesLoaded} bytes.");
}
private static async Task<int> DownloadDocsMainPageAsync()
{
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: About to start downloading.");
var client = new HttpClient();
byte[] content = await client.GetByteArrayAsync("https://learn.microsoft.com/en-us/");
Console.WriteLine($"{nameof(DownloadDocsMainPageAsync)}: Finished downloading.");
return content.Length;
}
}
// Output similar to:
// DownloadDocsMainPageAsync: About to start downloading.
// Main: Launched downloading.
// DownloadDocsMainPageAsync: Finished downloading.
// Main: Downloaded 27700 bytes.
Der Operand eines await
-Ausdrucks muss eine Benachrichtigung bereitstellen, wenn eine Aufgabe abgeschlossen ist. Im Allgemeinen wird eine Stellvertretung aufgerufen, wenn die Aufgabe abgeschlossen wird, entweder erfolgreich oder erfolglos. Der await
-Abschnitt der C#-Sprachspezifikation enthält die Details zur Implementierung dieser Benachrichtigungen.
Im vorherigen Beispiel wird die async-Main
-Methode verwendet. Weitere Informationen finden Sie im Abschnitt Der Operator „await“ in der Methode „Main“.
Hinweis
Eine Einführung in die asynchrone Programmierung finden Sie unter Asynchrone Programmierung mit „async“ und „await“. Die asynchrone Programmierung mit async
und await
folgt dem aufgabenbasierten asynchronen Muster.
Der Operator await
kann nur in einer Methode, einem Lambdaausdruck oder einer anonymen Methode verwendet werden, die von dem Schlüsselwort async geändert wird. Innerhalb einer Async-Methode können Sie den Operator await
nicht im Text einer synchronen Funktion, innerhalb des Blocks einer Lock-Anweisung oder in einem unsicheren Kontext verwenden.
Der Operand des Operators await
gehört normalerweise einem der folgenden .NET-Typen an: Task, Task<TResult>, ValueTask oder ValueTask<TResult>. Allerdings kann es sich bei jedem Awaitable-Ausdruck um den Operanden des Operators await
handeln. Weitere Informationen finden Sie im Abschnitt Awaitable-Ausdrücke der C#-Sprachspezifikation.
Der Ausdruck await t
ist vom Typ TResult
, wenn der Ausdruck t
vom Typ Task<TResult> oder ValueTask<TResult> ist. Wenn der Ausdruck t
vom Typ Task oder ValueTask ist, ist await t
vom Typ void
. In beiden Fällen löst await t
die Ausnahme erneut aus, wenn t
eine Ausnahme auslöst.
Asynchrone Datenströme und verwerfbare Objekte
Sie können die await foreach
-Anweisung verwenden, um einen asynchronen Datenstrom zu verarbeiten. Weitere Informationen finden Sie im Abschnitt foreach
-Anweisung im Artikel Iterationsanweisungen.
Sie können die await using
-Anweisung nutzen, um ein asynchron verwerfbares Objekt zu nutzen, d. h. ein Objekt eines Typs, der eine IAsyncDisposable-Schnittstelle implementiert. Weitere Informationen erhalten Sie im Abschnitt Verwenden von asynchron verwerfbar des Artikels Implementieren einer DisposeAsync-Methode.
Der Operator „await“ in der Methode „Main“
Die Main
-Methode, die den Einstiegspunkt der Anwendung darstellt, kann Task
oder Task<int>
zurückgeben. Deshalb kann es sich um eine Async-Methode handeln, sodass Sie den Operator await
im Text verwenden können. In früheren C#-Versionen können Sie den Wert der Eigenschaft Task<TResult>.Result der Instanz Task<TResult> abrufen, die von der entsprechenden Async-Methode zurückgegeben wird, um sicherzustellen, dass die Methode Main
darauf wartet, dass ein asynchroner Vorgang abgeschlossen wird. Für asynchrone Vorgänge, für die kein Wert zurückgegeben wird, können Sie die Methode Task.Wait aufrufen. Informationen zum Auswählen der Sprachversion finden Sie unter Auswählen der C#-Sprachversion.
C#-Sprachspezifikation
Weitere Informationen finden Sie im Abschnitt Await-Ausdrücke der C#-Sprachspezifikation.
Weitere Informationen
- C#-Operatoren und -Ausdrücke
- async
- Aufgabenbasiertes asynchrones Programmiermodell
- Asynchrone Programmierung
- Exemplarische Vorgehensweise: Zugreifen auf das Web mit „async“ und „await“
- Tutorial: Generieren und Nutzen asynchroner Datenströme
- .NET blog: How async/await really works in C# (.NET-Blog: Tatsächliche Funktionsweise von async/await in C#)