5.1C#异步编程运行机制

C#语言的异步编程是基于任务的异步编程(Task Asynchronous Programming,简写TAP)模型,该模型的核心是 Task 和 Task<T> 对象以及 async 和 await 关键字。

1.异步方法声明

async 返回类型 CurrentMethodAsync() 
{
    //启动多个任务,并将结果存储在任务变量
    返回类型1 任务变量1 = AnotherMethod1Async();
    返回类型2 任务变量2 = AnotherMethod2Async();
    返回类型N 任务变量N = AnotherMethodNAsync();

    //挂起当前异步方法,当任务变量有结果时,从任务变量查询结果
    //并将结果保存在变量
    类型1 变量1 = await 任务变量1;
    类型2 变量2 = await 任务变量2;
    类型N 变量N = await 任务变量N;
    
    //读取变量内容,返回值
    [return 表达式;]
}

async 修饰符声明 方法、lambda表达式、匿名方法是异步的。

await 运算符等待另一个异步方法返回的任务变量。仅允许在异步方法中且至少使用一个 await 运算符。

await 运算符会立即暂停往下执行同时将当前异步方法挂起,并且控制权返回到当前异步方法的调用方,当 任务变量 有结果时,控制权将在此处恢复继续执行,从 任务变量 查询结果并赋值给变量。

await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停其所属的方法。

通过这两个关键字,可以轻松地创建异步方法(几乎与创建同步方法一样轻松)。

2.返回类型

返回类型类型描述
Task引用类型如果方法内 return 语句不返回操作数 或 不含任何 return 语句,则将 Task 用作返回类型。
Task<TResult>引用类型如果方法内 return 语句的操作数返回类型为 TResult 类型,则将 Task<TResult> 用作返回类型。
void值类型如果要编写需要 void 返回类型的异步事件处理程序(async event handler)。
任何具有可访问的 GetAwaiter 方法的类型引用类型GetAwaiter 方法返回的awaiter类型的实例必须实现 System.Runtime.CompilerServices.ICriticalNotifyCompletion 接口且必须具有 System.Runtime.CompilerServices.AsyncMethodBuilderAttribute 特性。比如ValueTaskValueTask<TResult>
IAsyncEnumerable<T>引用类型 用于返回异步流的异步方法。

3.等待任务

用这个而不是这个应用场景
awaitTask.Wait 或 Task.Result检索后台任务的结果
await Task.WhenAnyTask.WaitAny等待任何任务完成
await Task.WhenAllTask.WaitAll等待所有任务完成
await Task.DelayThread.Sleep等待一段时间

4.运行机制

public async Task<int> GetUrlContentLengthAsync()
{
    var client = new HttpClient();

    Task<string> getStringTask =
        client.GetStringAsync("https://docs.microsoft.com/dotnet");

    DoIndependentWork();

    string contents = await getStringTask;

    return contents.Length;
}

void DoIndependentWork()
{
    Console.WriteLine("Working...");
}
5.1C#异步编程运行机制

运行机制基本分为两步:

4.1启动 Task<string>任务

Task<string> getStringTask =
    client.GetStringAsync("https://docs.microsoft.com/dotnet");

4.2等待 Task<string>任务

string contents = await getStringTask;

5.异步数据流

await foreach语句迭代异步数据流(实现IAsyncEnumerable<T>接口的集合类型)的实例。

static async IAsyncEnumerable<string> ReadWordsFromStreamAsync()
{
    string data =
        @"This is a line of text.
          Here is the second line of text.
          And there is one more for good measure.
          Wait, that was the penultimate line.";

    using var readStream = new StringReader(data);

    string line = await readStream.ReadLineAsync();
    while (line != null)
    {
        foreach (string word in line.Split(' ', StringSplitOptions.RemoveEmptyEntries))
        {
            yield return word;
        }

        line = await readStream.ReadLineAsync();
    }
}
await foreach (var item in ReadWordsFromStreamAsync())
{
    Console.WriteLine(item);
}

await foreach语句还可以迭代满足以下条件的任何类型的实例:

  • 类型具有public无参数的GetAsyncEnumerator方法(可以是类型的扩展方法),GetAsyncEnumerator方法的返回值具有publicCurrent属性。
  • 类型具有public的无参数MoveNextAsync方法,MoveNext方法的返回值为Task<bool>ValueTask<bool>或 任何其它awaitable类型,awaitable类型的awaiter的 GetResult 方法返回 bool 值。

原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/csharp/csharplang/11607.html

(0)
上一篇 2021年5月1日 02:26
下一篇 2021年5月2日 02:32

相关推荐

  • 3.5C#引用类型之接口(Interface)

    1.接口声明 接口包含一组非抽象class或struct必须实现的相关功能的定义。 2.继承 接口 可以继承自多个基接口。 3.实现 3.1实现 类 或 结构 可以实现多个接口,实现接口的类或结构必须实现其所有未提供默认实现的成员并匹配接口中的成员签名,非必须重写实现具有默认实现的成员。 3.2默认实现 接口…

    C#语言教程 2021年3月5日
    06910
  • 3.6C#引用类型之字符串(String)

    1.字符串声明 2.获取字符串长度 3.访问字符串 4.字符串连接 可使用 + 运算符 或 += 运算符连接字符串。 5.字符串内插(Interpolation) 若要将字符串标识为字符串内插(Interpolation),可在该字符串 ” 左引号前面加上 $ 美元符号(&nbs…

    C#语言教程 2021年3月6日
    05850
  • 1.3C#语言的运算符(Operator)和表达式(Expression)

    1.一元运算符 运算符 描述 +x 一元 + 运算符返回其操作数的值。 -x 一元 – 运算符对其操作数的数值取负。 ++x ++x 的结果是按 1 递增其操作数后的 x 的值。 –x –x 的结果是按 1 递减其操作数后的 …

    C#语言教程 2021年1月3日
    08260

发表回复

登录后才能评论