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...");
}
.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日 17:26
下一篇 2021年5月2日 02:32

相关推荐

  • 3.10C#引用类型之委托(Delegate)

    委托类型派生自 System.Delegate 类。 1.委托声明 委托 表示对具有 特定参数列表 和 返回类型 的方法的引用。 委托 可认为是函数式语言里的“函数类型”,通过委托,可以将方法视为可赋值给变量或作为参数传递的实体。 委托还类似于其它一些语言中存在的“函数指针”概念。 具有相同参数列表和返回类型…

    C#语言教程 2021年3月10日
    02710
  • 3.7C#引用类型之数组(Array)

    数组(Array)是一种数据结构,可以用一个统一的数组名和不同的下标(或称索引,index)来确定数组中唯一的元素。根据数组的维度,可以将其分为一维数组、多维数组和交错数组。 数组中的元素是有序的,包含 Length 个元素的数组从 0 索引到 Length-1。 数组…

    C#语言教程 2021年3月7日
    02710
  • 1.4C#语言的类型(Type)

    C # 语言有两种类型:值类型 和 引用类型。值类型的变量直接存储数据,而引用类型的变量则存储对数据(称为“对象”)的引用。 System.Object类(别名object) 是所有类型的最终基类。值类型 派生自 System.ValueType类 (派生自 System.Object类)。派生自&…

    C#语言教程 2021年1月4日
    04480

发表评论

登录后才能评论