dotnet 使用 TaskTupleAwaiter 同时等待多个任务简化代码写法
在某些业务逻辑下,需要同时等待多个任务执行完成,才能继续往下执行后续逻辑。等待任务执行的逻辑,大部分情况下需要使用到 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 进行等待,只是对此进行封装
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 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 同时等待多个任务简化代码写法的更多相关文章
- Selenium三种等待元素的方式及代码,需要特别注意implicitlyWait的用法
一.显式等待 1.显式等待: 就是明确的要等到某个元素的出现或者是某个元素的可点击等条件,等不到,就一直等,除非在规定的时间之内都没找到,那么就跳出Exception. 2.代码: new WebDr ...
- Java线程的等待与唤醒完整示例代码
项目结构: 资源类: 输入线程: 输出线程: 测试: 人妖问题发生: 线程安全问题的解决方法: 调用Object的wait()和notify()方法时需注意:必须是锁对象方可调用,否则将抛出无效的监 ...
- 关于InvokeRequired与Invoke
from:http://www.th7.cn/Program/net/201306/140033.shtml Windows 窗体中的控件被绑定到特定的线程,不具备线程安全性.因此,如果从另一个线程调 ...
- ASP.NET Core 中文文档 第二章 指南(8) 使用 dotnet watch 开发 ASP.NET Core 应用程序
原文:Developing ASP.NET Core applications using dotnet watch 作者:Victor Hurdugaci 翻译:谢炀(Kiler) 校对:刘怡(Al ...
- 使用 dotnet watch 开发 ASP.NET Core 应用程序
使用 dotnet watch 开发 ASP.NET Core 应用程序 原文:Developing ASP.NET Core applications using dotnet watch作者:Vi ...
- dotnet 替换 ASP.NET Core 的底层通讯为命名管道的 IPC 库
这是一个用于本机多进程进行 IPC 通讯的库,此库的顶层 API 是采用 ASP.NET Core 的 MVC 框架,其底层通讯不是传统的走网络的方式,而是通过 dotnetCampus.Ipc 开源 ...
- dotnet 6 在 Win7 系统证书链错误导致 HttpWebRequest 内存泄露
本文记录我将应用迁移到 dotnet 6 之后,在 Win7 系统上,因为使用 HttpWebRequest 访问一个本地服务,此本地服务开启 https 且证书链在此 Win7 系统上错误,导致应用 ...
- DotNet Run 命令介绍
前言 本篇主要介绍 asp.net core 中,使用 dotnet tools 运行 dotnet run 之后的系统执行过程. 如果你觉得对你有帮助的话,不妨点个[推荐]. 目录 dotnet r ...
- .NET跨平台之旅:探秘 dotnet run 如何运行 .NET Core 应用程序
自从用 dotnet run 成功运行第一个 "Hello world" .NET Core 应用程序后,一直有个好奇心:dotnet run 究竟是如何运行一个 .NET Cor ...
- dotnet tools 运行 dotnet run
dotnet tools 运行 dotnet run dotnet run 命令介绍 前言 本篇主要介绍 asp.net core 中,使用 dotnet tools 运行 dotnet run 之后 ...
随机推荐
- 01.Android线程池实践基础
目录介绍 01.实际开发问题 02.线程池的优势 03.ThreadPoolExecutor参数 04.ThreadPoolExecutor使用 05.线程池执行流程 06.四种线程池类 07.exe ...
- 常用命令--htpasswd--(网站加密)
常用命令htpasswd(网站加密) 常用选项 htpasswd 是一个用于创建和管理HTTP基本认证密码文件的命令行工具,通常与Apache Web服务器一起使用.以下是 htpasswd 常用选项 ...
- KafkaProducerDemo
package com.lxw.kafkademo; import org.apache.kafka.clients.producer.KafkaProducer; import org.apache ...
- PS的流水灯设计分析
PS的流水灯设计分析 1.实验原理 PS设计流水灯就是采用ARM的硬核实现流水灯设计.ARM内核采用的就是一个可以执行软件程序的平台.这里采用C语言设计.基于前面构建的GPIO外设的硬件平台,这里实现 ...
- CornerNet:经典keypoint-based方法,通过定位角点进行目标检测 | ECCV2018
论文提出了CornerNet,通过检测角点对的方式进行目标检测,与当前的SOTA检测模型有相当的性能.CornerNet借鉴人体姿态估计的方法,开创了目标检测领域的一个新框架,后面很多论文都基于Cor ...
- KingbaseES V8R6 中unlogged表
前言 KingbaseESV8R6有一种表称为unlogged,在该表新建的索引也属于unlogged.和普通表的区别是,对该表进行DML操作时候不将该表的变更记录变更写入到wal文件中.在数据库异常 ...
- C语言线程安全问题
线程安全问题 #include <stdio.h> #include <tinycthread.h> #include <io_utils.h> int count ...
- DIY 3 种分库分表分片算法,自己写的轮子才吊!
大家好,我是小富- 前言 本文是<ShardingSphere5.x分库分表原理与实战>系列的第六篇,书接上文实现三种自定义分片算法.通过自定义算法,可以根据特定业务需求定制分片策略,以满 ...
- Zookeeper解决了什么问题?
在公司中用到了zookeeper协调分布式系统,在这里记录下. (一). 首先是什么? 是一种适用于分布式应用程序的高性能协调服务.它在一个简单的界面中公开常见服务(如命名.配置管理.同步和组服务), ...
- Java 数学运算与条件语句全解析
Java Math Java 的 Math 类 拥有许多方法,允许您在数字上执行数学任务. 常用方法: Math.max(x, y): 找到 x 和 y 的最大值 Math.min(x, y): 找到 ...