C Sharp/The .NET Framework/async

语法编辑

运算符await挂起(suspend)对其后运算数中的async方法(或者async Task对象)的求值,直至async方法包含的异步操作完成才返回其运算数的值(如果有)。如果一个async方法被运算符await挂起,则该方法的caller获得控制权恢复执行。async方法中的异常会在运算符await中重新抛出(rethrow)。 直观的示例:

using System;
using System.Net.Http;
using System.Threading.Tasks;

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://docs.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 126809 bytes.

await foreach语句消费异步数据流。

await using语句在异步可回收(disposable)对象上工作。

例子编辑

using System;
using System.Threading.Tasks;

namespace AsyncWarning
{
    class Program
    {
        static async Task Main()
        {
            Console.WriteLine("Entering Main() application entry point.");

            int millisecondsDelay = 2000;
            await CallingMethodAsync(millisecondsDelay);

            Console.WriteLine("Exiting Main() application entry point.");

            await Task.Delay(millisecondsDelay + 500);
        }

        static async Task CallingMethodAsync(int millisecondsDelay)
        {
            Console.WriteLine("  Entering calling method.");

            // Call #1.
            // Call an async method. Because you don't await it, its completion
            // isn't coordinated with the current method, CallingMethodAsync.
            // The following line causes warning CS4014.
            // CalledMethodAsync(millisecondsDelay);

            // Call #2.
            // To suppress the warning without awaiting, you can assign the
            // returned task to a variable. The assignment doesn't change how
            // the program runs. However, recommended practice is always to
            // await a call to an async method.

            // Replace Call #1 with the following line.
            //Task delayTask = CalledMethodAsync(millisecondsDelay);

            // Call #3
            // To contrast with an awaited call, replace the unawaited call
            // (Call #1 or Call #2) with the following awaited call. Best
            // practice is to await the call.

            // await CalledMethodAsync(millisecondsDelay);

            Console.WriteLine("  Returning from calling method.");
        }

        static async Task CalledMethodAsync(int millisecondsDelay)
        {
            Console.WriteLine("    Entering called method, starting and awaiting Task.Delay.");

            await Task.Delay(millisecondsDelay);

            Console.WriteLine("    Task.Delay is finished--returning from called method.");
        }
    }

    // Output with Call #1 or Call #2. (Wait for the last line to appear.)

    // Entering Main() application entry point.
    //   Entering calling method.
    //     Entering called method, starting and awaiting Task.Delay.
    //   Returning from calling method.
    // Exiting Main() application entry point.
    //     Task.Delay is finished--returning from called method.

    // Output with Call #3, which awaits the call to CalledMethodAsync.

    // Entering Main() application entry point.
    //   Entering calling method.
    //     Entering called method, starting and awaiting Task.Delay.
    //     Task.Delay is finished--returning from called method.
    //   Returning from calling method.
    // Exiting Main() application entry point.
}