一.async 和 await 概述

使用 async 关键字可将方法(包括匿名方法和lambda表达式)指定为异步。 如下示例定义了一个名为 ExampleMethodAsync 的异步方法:

public async Task<int> ExampleMethodAsync()
{
    //...
}

标记的异步方法可以使用 await 关键字来指定暂停点。await 告诉编译器,在等待的异步进程完成之前,异步方法无法继续超过该点。 同时,控件将返回到异步方法的调用方。

string contents = await httpClient.GetStringAsync(requestUrl);

二.Demo1 展示和分析

自定义一个异步方法【GetUrlLengAsync】,其内调用并等待异步方法【GetStringAsync】,将返回值保存并返回。Main方法也定义为异步方法,其等待【GetUrlLengAsync】执行完成并打印时间。

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

namespace Console0719
{
    public class DelegateExample
    {
        static async Task<int> GetUrlLengAsync()//Task<int>:返回int,用Task<int>
        {
            var client = new HttpClient();
            Task<string> getStringTask = client.GetStringAsync("https://learn.microsoft.com/dotnet");//调用异步方法:client.GetStringAsync
            string contents = await getStringTask; //等待异步方法完成:await + 返回值
            Console.WriteLine("In GetUrlLengAsync, func GetStringAsync finished:" + DateTime.Now.ToString("HH:mm:ss"));
            return contents.Length;
        }
        static async Task Main(string[] args)//async:将方法标记为异步方法;   Task:无返回值用task
        {
            Console.WriteLine("Before call GetUrlLengAsync:" + DateTime.Now.ToString("HH:mm:ss"));
            await GetUrlLengAsync();//调用异步方法并等待:await+方法名()
            Console.WriteLine("After call GetUrlLengAsync:" + DateTime.Now.ToString("HH:mm:ss"));
            Console.ReadKey();
        }
    }
}

三.Demo2 展示和分析

自定义一个异步方法【GetUrlLengAsync】,其内调用并等待异步方法【GetStringAsync】,将返回值保存并返回。Main方法不是异步方法,不等待【GetUrlLengAsync】完成并打印时间。

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

namespace Console0719
{
    public class DelegateExample
    {
        static async Task<int> GetUrlLengAsync()//Task<int>:返回int,用Task<int>
        {
            var client = new HttpClient();
            Task<string> getStringTask = client.GetStringAsync("https://learn.microsoft.com/dotnet");//保存异步方法返回值
            string contents = await getStringTask; //等待异步方法完成:await + 返回值
            Console.WriteLine("In GetUrlLengAsync, func GetStringAsync finished:" + DateTime.Now.ToString("HH:mm:ss"));
            return contents.Length;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Before call GetUrlLengAsync:" + DateTime.Now.ToString("HH:mm:ss"));
            GetUrlLengAsync();
            Console.WriteLine("After call GetUrlLengAsync:" + DateTime.Now.ToString("HH:mm:ss"));
            Console.ReadKey();
        }
    }
}

四.异步方法的精简结论和注意事项

4.1 异步方法的调用和等待结果(Demo1)

  • await+方法名()  (推荐)
await GetUrlLengAsync();//调用异步方法并等待:await+方法名()
  • 先保存异步方法返回值,再等待异步方法完成:await + 返回值
Task<string> getStringTask = client.GetStringAsync("https://learn.microsoft.com/dotnet");//保存异步方法返回值
string contents = await getStringTask; //等待异步方法完成:await + 返回值

4.2 用 async 修饰 main 方法(Demo1)

Main 可以返回 void、 int、 Task或 Task<int>,仅当Main返回TaskTask<int>时,可以用 async 修饰 main

4.3 在调用处不等待异步方法完成的情形(Demo2)

异步方法调用后的逻辑和异步方法返回值无关时,在调用处可不等待异步方法执行完成

4.4 异步方法不包含await的情况

如果 async 关键字修改的方法不包含 await,该方法将同步执行。 编译器不会报错,会发出警告

4.5 命名约定

按照惯例,返回常见可等待类型的方法(例如,TaskTask<T>ValueTaskValueTask<T>)应具备以“Async”结尾的名称。 启动异步操作但不返回可等待类型的方法,不应具有以“Async”结尾的名称,但可能以“Begin”、“Start”或其他一些动词开头,表明此方法不会返回或抛出操作的结果。

五.异步方法返回类型

异步方法可具有以下返回类型:

  • Task:无返回值
  • Task<TResult>:返回TResult类型
  • void:仅当需要将异步方法注册到事件中时,使用void返回值

六.参考

async (C# 参考)

使用 async 和 await 进行异步编程

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐