在某些业务逻辑下,需要同时等待多个任务执行完成,才能继续往下执行后续逻辑。等待任务执行的逻辑,大部分情况下需要使用到 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. 记录--CSS 滚动驱动动画 scroll()

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 CSS 滚动驱动动画 scroll() animation-timeline 通过 scroll() 指定可滚动元素与滚动轴来为容器动画提 ...

  2. 如何从容的打包上传图片对象--File,Blob,BASE64详解及转换方法

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 File() File() 构造器创建新的 File 对象实例. 语法 var myFile = new File(bits, name[ ...

  3. 记录--uni-app adb安卓wifi无线调试

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 方法一 adb connect连接调试 前提条件: 电脑已安装adb工具 手机和电脑连接的同一个WIFI CMD进入到adb工具所在目录, ...

  4. ElasticSearch8 - SpringBoot整合ElasticSearch

    前言 springboot 整合 ES 有两种方案,ES 官方提供的 Elasticsearch Java API Client 和 spring 提供的 [Spring Data Elasticse ...

  5. C# 剪裁图片

    /// <summary> /// 剪裁图片 /// </summary> /// <param name="src">原图片</para ...

  6. vim-plus install

    1.输入:git clone https://github.com/chxuan/vimplus.git ~/.vimplus 2.输入:cd ~/.vimplus 3.输入:./install.sh ...

  7. 一个可以让你有更多时间摸鱼的WPF控件(二)

    前言 上文介绍了如何通过一个Form自定义控件来简化数据的录入,并自动实现数据校验,自动布局排列等功能.本文继续介绍如何优化表格控件的使用,缩减代码量,实现工作效率的提升. 一.功能实现 上文中分析了 ...

  8. ET8.1(一)简介

    此系列文章逐个内容讲解ET8.1的新特性. ET8.1 发布,带来以下新特性: 1. 多线程多进程架构,架构更加灵活强大,多线程设计详细内容请看多线程设计课程   2. 抽象出纤程(Fiber)的概念 ...

  9. WPF动画教程(PointAnimationUsingPath的使用)

    PointAnimationUsingPath的介绍 PointAnimationUsingPath 是 WPF 中的一个类,它用于创建一个动画,该动画会沿着指定的路径移动一个点. 关于 PointA ...

  10. #SG函数#HDU 1848 Fibonacci again and again

    题目 分析 可取状态只能是斐波那契数,求出SG函数 然后判断三个数sg函数异或和不为0先手必胜 代码 #include <cstdio> #include <cctype> # ...