在某些业务逻辑下,需要同时等待多个任务执行完成,才能继续往下执行后续逻辑。等待任务执行的逻辑,大部分情况下需要使用到 Task.WhenAll 方法,代码行数不少。另外,在需要获取多个异步任务的返回值的逻辑上,整体的逻辑代码量看起来也不少。本文将和大家介绍 TaskTupleAwaiter 库,通过 TaskTupleAwaiter 库可以方便等待多个任务执行完成,且方便获取各个异步任务的返回值

假定有两个异步任务方法,如以下代码,期望等待这两个方法执行完成,获取到结果,再执行后续逻辑

Task<string> GetFoo1Async() => Task.Run(() => "Foo1");

Task<string> GetFoo2Async() => Task.Run(() => "Foo2");

传统方法是通过 Task.WhenAll 等待任务完成,再获取对应的值,如以下代码

var task1 = GetFoo1Async();
var task2 = GetFoo2Async(); await Task.WhenAll(task1, task2); var (foo1, foo2) = (task1.Result, task2.Result);

但千万不要先等待第一个任务执行完成,再等待第二个任务执行完成哦,如果是如以下代码的写法,自然会没有充分利用资源,第二个任务还在等待中

var foo1 = await GetFoo1Async();
var foo2 = await GetFoo2Async();

在异步任务超过 3 个之后,代码逻辑的长度自然就很长了。接下来看看本文介绍的 TaskTupleAwaiter 库的优化后的写法

使用 TaskTupleAwaiter 库之后的可以简化为如下代码

var (foo1, foo2) = await (GetFoo1Async(), GetFoo2Async());

可以看到一行就实现上面大概用了 4 行才能完成的任务,随着异步任务的数量的增加,优化力度也会更加大,同时也能解决在返回值相同的时候,不小心写过等待的任务的坑

按照惯例,使用 TaskTupleAwaiter 库的第一步就是安装 NuGet 包,对于 SDK 格式的 csproj 项目文件,可以在 csproj 里面添加如下代码用来安装

  <ItemGroup>
<PackageReference Include="TaskTupleAwaiter" Version="2.0.0" />
</ItemGroup>

这个库的使用方法十分简单,只是创建一个扩展类,里面就对 ValueTuple 扩展了 GetAwaiter 方法,根据 C# await 高级用法 博客可以了解到,对于 await 等待来说,只需要等待的类型存在 GetAwaiter 方法且此 GetAwaiter 方法返回一个实现了等待相关方法的类型的对象即可

例如对于由三个 Task 任务组成的 ValueTuple 加上可等待的功能的扩展方法可以是如下代码

	public static TupleTaskAwaiter<T1, T2, T3> GetAwaiter<T1, T2, T3>(this (Task<T1>, Task<T2>, Task<T3>) tasks) =>
new(tasks); public readonly record struct TupleTaskAwaiter<T1, T2, T3> : ICriticalNotifyCompletion
{
private readonly (Task<T1>, Task<T2>, Task<T3>) _tasks;
private readonly TaskAwaiter _whenAllAwaiter; public TupleTaskAwaiter((Task<T1>, Task<T2>, Task<T3>) tasks)
{
_tasks = tasks;
_whenAllAwaiter = Task.WhenAll(tasks.Item1, tasks.Item2, tasks.Item3).GetAwaiter();
} public bool IsCompleted =>
_whenAllAwaiter.IsCompleted; public void OnCompleted(Action continuation) =>
_whenAllAwaiter.OnCompleted(continuation); [SecurityCritical]
public void UnsafeOnCompleted(Action continuation) =>
_whenAllAwaiter.UnsafeOnCompleted(continuation); public (T1, T2, T3) GetResult()
{
_whenAllAwaiter.GetResult();
return (_tasks.Item1.Result, _tasks.Item2.Result, _tasks.Item3.Result);
}
}

GetAwaiter 扩展方法,给 (Task<T1>, Task<T2>, Task<T3>) 扩展了可等待的方法,如此即可使用 await 进行等待

通过 TupleTaskAwaiter 实现具体的等待逻辑,核心实现依然是 Task.WhenAll 进行等待,只是对此进行封装

本文的代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 37c7473807581cde1215374856e5fd8f285c21a9

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 37c7473807581cde1215374856e5fd8f285c21a9

获取代码之后,进入 JahawciceyainalljoHeneeqearhi 文件夹

既然实现如此简单,那自然还有其他的库也可以实现相同的功能。例如 UniTask 库,这是一个支持在 Unity 更方便做异步的库,开源地址: https://github.com/Cysharp/UniTask

在非 Unity 下也依然可用,使用之后有两个可选写法,一个是 UniTask.WhenAll 等待方法,另一个是更加简洁的和 TupleTaskAwaiter 几乎完全相同的直接等待的方法,如以下的例子

    var task1 = GetTextAsync(UnityWebRequest.Get("http://google.com"));
var task2 = GetTextAsync(UnityWebRequest.Get("http://bing.com"));
var task3 = GetTextAsync(UnityWebRequest.Get("http://yahoo.com")); // 方法一是通过 UniTask.WhenAll 等待
// concurrent async-wait and get results easily by tuple syntax
var (google, bing, yahoo) = await UniTask.WhenAll(task1, task2, task3); // 方法二是直接等待
// shorthand of WhenAll, tuple can await directly
var (google2, bing2, yahoo2) = await (task1, task2, task3);

dotnet 使用 TaskTupleAwaiter 同时等待多个任务简化代码写法的更多相关文章

  1. Selenium三种等待元素的方式及代码,需要特别注意implicitlyWait的用法

    一.显式等待 1.显式等待: 就是明确的要等到某个元素的出现或者是某个元素的可点击等条件,等不到,就一直等,除非在规定的时间之内都没找到,那么就跳出Exception. 2.代码: new WebDr ...

  2. Java线程的等待与唤醒完整示例代码

    项目结构: 资源类: 输入线程:  输出线程: 测试: 人妖问题发生: 线程安全问题的解决方法: 调用Object的wait()和notify()方法时需注意:必须是锁对象方可调用,否则将抛出无效的监 ...

  3. 关于InvokeRequired与Invoke

    from:http://www.th7.cn/Program/net/201306/140033.shtml Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性.因此,如果从另一个线程调 ...

  4. ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序

    原文:Developing ASP.NET Core applications using dotnet watch 作者:Victor Hurdugaci 翻译:谢炀(Kiler) 校对:刘怡(Al ...

  5. 使用 dotnet watch 开发 ASP.NET Core 应用程序

    使用 dotnet watch 开发 ASP.NET Core 应用程序 原文:Developing ASP.NET Core applications using dotnet watch作者:Vi ...

  6. dotnet 替换 ASP.NET Core 的底层通讯为命名管道的 IPC 库

    这是一个用于本机多进程进行 IPC 通讯的库,此库的顶层 API 是采用 ASP.NET Core 的 MVC 框架,其底层通讯不是传统的走网络的方式,而是通过 dotnetCampus.Ipc 开源 ...

  7. dotnet 6 在 Win7 系统证书链错误导致 HttpWebRequest 内存泄露

    本文记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,因为使用 HttpWebRequest 访问一个本地服务,此本地服务开启 https 且证书链在此 Win7 系统上错误,导致应用 ...

  8. DotNet Run 命令介绍

    前言 本篇主要介绍 asp.net core 中,使用 dotnet tools 运行 dotnet run 之后的系统执行过程. 如果你觉得对你有帮助的话,不妨点个[推荐]. 目录 dotnet r ...

  9. .NET跨平台之旅:探秘 dotnet run 如何运行 .NET Core 应用程序

    自从用 dotnet run 成功运行第一个 "Hello world" .NET Core 应用程序后,一直有个好奇心:dotnet run 究竟是如何运行一个 .NET Cor ...

  10. dotnet tools 运行 dotnet run

    dotnet tools 运行 dotnet run dotnet run 命令介绍 前言 本篇主要介绍 asp.net core 中,使用 dotnet tools 运行 dotnet run 之后 ...

随机推荐

  1. [.NET项目实战] Elsa开源工作流组件应用(二):内核解读

    @ 目录 定义 变量 内存寄存器类 寄存器中的存储区块类 变量到存储的映射类 上下文对象 活动上下文(ActivityExecutionContext) 工作流执行上下文(WorkflowExecut ...

  2. 基于R语言的GD库实现地理探测器并自动将连续变量转为类别变量

      本文介绍基于R语言中的GD包,依据栅格影像数据,实现自变量最优离散化方法选取与执行,并进行地理探测器(Geodetector)操作的方法.   首先,在R语言中进行地理探测器操作,可通过geode ...

  3. 【JVM】关于JVM,你需要知道这些!!

    写在前面 最近,一直有小伙伴让我整理下关于JVM的知识,经过十几天的收集与整理,初版算是整理出来了.希望对大家有所帮助. JDK 是什么? JDK 是用于支持 Java 程序开发的最小环境. Java ...

  4. #点分治,树状数组#洛谷 5311 [Ynoi2011] 成都七中

    题目 给你一棵 \(n\) 个节点的树,每个节点有一种颜色,有 \(m\) 次查询操作. 查询操作给定参数 \(l\) \(r\) \(x\),需输出: 将树中编号在 \([l,r]\) 内的所有节点 ...

  5. #期望,树的直径#51nod 1803 森林直径

    题目 有一棵 \(n\) 个结点的树,按顺序给出树边 \((fa[i],i)\), \(Q\) 次询问查询如果只选取第 \([l,r]\) 条树边,问森林的直径 \(fa[i]\) 的生成方式为 \( ...

  6. OpenHarmony技术日全面解读3.1 Release版本,系统基础能力再升级

    4 月 25 日,OpenAtom OpenHarmony(以下简称"OpenHarmony")技术日在深圳举办,对 OpenHarmony 3.1 Release 版本核心技术进 ...

  7. 快速加入Health Kit,一文了解审核流程

    HUAWEI Health Kit是为华为生态应用打造的基于华为帐号和用户授权的运动健康数据开放平台. 在获取用户授权后,开发者可以使用Health Kit提供的开放能力获取运动健康数据,基于多种类型 ...

  8. 我只用了3步,实现了一个逼真的3D场景渲染

    给3D模型及环境场景渲染出兼具质感和真实感的材质效果,需要经历几步? 显然,目前的3D模型材质渲染技术,还无法实现简单几步就能搞定的标准化作业来量化,完成一个质量过关的3D模型渲染,一般需要: 1.准 ...

  9. DEB打包教程

    一.deb简介 deb是一种安装包的格式,linux上常见的安装包主要是deb.rpm 二.deb简单使用 # deb安装 sudo dpkg -i webcamera_1.0_amd64.deb # ...

  10. JS判断浏览器是否是IE

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...