【C# Task】 ValueTask/Task<TResult>
概要
1、如果异步方法的使用者使用 Task.WhenAll 或 Task.WhenAny,则在异步方法中使用 ValueTask<T> 作为返回类型可能会产生高昂的成本。这是因为您需要使用 AsTask 方法将 ValueTask<T> 转换为 Task<T>这将产生一个分配,如果首先使用了缓存的 Task<T>,则可以轻松避免这种分配
2、每个值任务只能使用一次。此处的"消费"一词意味着 ValueTask 可以异步等待(等待)操作完成,或者利用 AsTask 将 ValueTask 转换为任务。但是,一个值任务只应使用一次,之后应忽略值任务<T>。
如何在 C 中使用 ValueTask#
利用 C# 中的 ValueTask,避免在从异步方法返回任务对象时进行分配
异步编程已经使用了相当长一段时间。近年来,随着异步和等待关键字的引入,它变得更加强大。您可以利用异步编程来提高应用程序的响应能力和吞吐量。
C# 中异步方法的建议返回类型是 Task。如果要编写返回值的异步方法,则应返回 Task<T>。如果要编写事件处理程序,可以改为返回 void。在 C# 7.0 之前,异步方法可以返回 Task、Task<T> 或 void。从 C# 7.0 开始,异步方法还可以返回 ValueTask(作为 System.Threading.Tasks.Extensions 包的一部分提供)或 ValueTask<T>。本文讨论了如何在 C# 中使用 ValueTask。
为什么我应该使用 ValueTask?
任务表示某个操作的状态,即操作是否已完成、是否取消等。异步方法可以返回 Task 或 ValueTask。
现在,由于 Task 是引用类型,因此从异步方法返回 Task 对象意味着每次调用该方法时都要在托管堆上分配该对象。因此,使用 Task 时需要注意的一点是,每次从方法返回 Task 对象时,都需要在托管堆中分配内存。如果方法正在执行的操作的结果立即可用或同步完成,则不需要此分配,因此成本会变得高昂。
这正是ValueTask的救星。ValueTask<T>提供了两个主要优点。首先,ValueTask<T>提高了性能,因为它不需要堆分配,其次,它既简单又灵活地实现。当结果立即可用时,通过从异步方法返回 ValueTask<T> 而不是 Task<T>,可以避免不必要的分配开销,因为此处的"T"表示结构,而 C# 中的结构是值类型(与 Task<T> 中的"T"相反,后者表示类)。
Task 和 ValueTask 表示 C# 中的两种主要的"可等待"类型。请注意,您无法阻止值任务。如果需要阻止,则应使用 AsTask 方法将 ValueTask 转换为任务,然后阻止该引用 Task 对象。
另请注意,每个值任务只能使用一次。此处的"消费"一词意味着 ValueTask 可以异步等待(等待)操作完成,或者利用 AsTask 将 ValueTask 转换为任务。但是,一个值任务只应使用一次,之后应忽略值任务<T>。
C# 中的值任务示例
假设您有一个返回 Task 的异步方法。您可以利用 Task.FromResult 创建 Task 对象,如下面给出的代码片段所示。
public Task<int> GetCustomerIdAsync()
{
return Task.FromResult(1);
}
上面的代码片段不会创建整个异步状态机魔术,但它会在托管堆中分配一个 Task 对象。若要避免此分配,您可能希望改为利用 ValueTask,如下面给出的代码段所示。
public ValueTask<int> GetCustomerIdAsync()
{
return new ValueTask(1);
}
以下代码段阐释了 ValueTask 的同步实现。
public interface IRepository<T>
{
ValueTask<T> GetData();
}
存储库类扩展 IRepository 接口并实现其方法,如下所示。
public class Repository<T> : IRepository<T>
{
public ValueTask<T> GetData()
{
var value = default(T);
return new ValueTask<T>(value);
}
}
下面介绍了如何从 Main 方法调用 GetData 方法。
static void Main(string[] args)
{
IRepository<int> repository = new Repository<int>();
var result = repository.GetData();
if(result.IsCompleted)
Console.WriteLine("Operation complete...");
else
Console.WriteLine("Operation incomplete...");
Console.ReadKey();
}
现在,让我们向存储库中添加另一个方法,这次是名为 GetDataAsync 的异步方法。以下是修改后的 IRepository 接口的外观。
public interface IRepository<T>
{
ValueTask<T> GetData();
ValueTask<T> GetDataAsync();
}
GetDataAsync 方法由 Repository 类实现,如下面给出的代码片段所示。
public class Repository<T> : IRepository<T>
{
public ValueTask<T> GetData()
{
var value = default(T);
return new ValueTask<T>(value);
}
public async ValueTask<T> GetDataAsync()
{
var value = default(T);
await Task.Delay(100);
return value;
}
}
何时应在 C# 中使用 ValueTask?
尽管 ValueTask 提供了许多好处,但使用 ValueTask 代替 Task 需要一些权衡。ValueTask 是具有两个字段的值类型,而 Task 是具有单个字段的引用类型。因此,使用 ValueTask 意味着处理更多数据,因为方法调用将返回两个数据字段而不是一个字段。此外,如果等待返回 ValueTask 的方法,则该异步方法的状态机也会更大,因为在 Task 的情况下,它必须容纳包含两个字段的结构,而不是单个引用。
此外,如果异步方法的使用者使用 Task.WhenAll 或 Task.WhenAny,则在异步方法中使用 ValueTask<T> 作为返回类型可能会产生高昂的成本。这是因为您需要使用 AsTask 方法将 ValueTask<T> 转换为 Task<T>这将产生一个分配,如果首先使用了缓存的 Task<T>,则可以轻松避免这种分配。
这是经验法则。当您有一段始终是异步的代码时,即当操作不会立即完成时,请使用 Task。当异步操作的结果已经可用或已有缓存的结果时,请利用 ValueTask。无论哪种方式,您都应该在考虑 ValueTask 之前执行必要的性能分析。
【C# Task】 ValueTask/Task<TResult>的更多相关文章
- 【C# Task】理解Task中的ConfigureAwait配置同步上下文
原文:https://devblogs.microsoft.com/dotnet/configureawait-faq/ 作者:Stephen 翻译:xiaoxiaotank 静下心来,你一定会有收获 ...
- 【SRM-06 D】五色战队&&【codeforces 788E】 New task
原题链接:788E - New task Description 游行寺家里人们的发色多种多样,有基佬紫.原谅绿.少女粉.高级黑.相簿白等. 日向彼方:吾令人观其气,气成五彩,此天子气也. 琉璃:我们 ...
- 【ZOJ 3844】Easy Task
题意 每次把序列中最大的数a的一个和最小的数b的一个变成a-b.求最后是否能使序列里的数全部相同,能则输出这个相同的数. 分析 一定是有解的,不断减少最大数的个数,最大数减少为0个时,就是减少了不同数 ...
- 【C# Task】开篇
概览 在学task类之前必须学习线程的知识. 以下是task命名空间的类的结构图 1.2种任务类型: 有返回值task<TResult> .无返回值task. 2.2座任务工厂 TaskF ...
- 【.NET+MQTT】.NET6 环境下实现MQTT通信,以及服务端、客户端的双边消息订阅与发布的代码演示
前言: MQTT广泛应用于工业物联网.智能家居.各类智能制造或各类自动化场景等.MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,在很多受限的环境下,比如说机器与机器通信.机器与物联网通信等. ...
- 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程
反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) 背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...
- 【30.93%】【codeforces 558E】A Simple Task
time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...
- 【EWM系列】SAP EWM创建warehouse task的函数
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP EWM创建warehouse ...
- 【C# task】TaskContinuationOptions 位枚举
TaskContinuationOptions 根据 TaskContinuationOptions 的不同,出现了三个分支 LongRunning:独立线程,和线程池无关 包含 PreferFair ...
随机推荐
- Cesium源码剖析---视频投影
Cesium中的视频投影是指将视频作为一种物体材质,实现在物体上播放视频的效果.这个功能在Cesium早期版本中就支持了,在Code Example中有一个示例.今天就来分析一下其内部实现原理. 1. ...
- (3)ESP32 Python 制作一个办公室温度计
因为经常在办公室里面不知道实际室内温度是多少,所以用ESP32做了一个工具来进行温度&湿度的监测.在之前的文章当中,已经完成了ESP32的数据上云工作,如果要进行温度/湿度的检测.从原理上就是 ...
- openSUSE修改grub来修复对win8的引导
前言:继上一次安装试用各版本linux发行版后,由于做项目将机器纯windows了一把,现在又想安回centos,各种挫折折腾两天玩残一个u盘日,其中包括自己本本的原装系统也崩了,各种泪奔,下面记录一 ...
- 如何理解python中的cmp_to_key()函数
cmp_to_key() 在functools包里的函数,将老式的比较函数(cmp function)转化为关键字函数(key function). 与接受key function的工具一同使用(如 ...
- VUE3 之 组件间事件通信 - 这个系列的教程通俗易懂,适合新手
1. 概述 相关定律告诉我们:这个世界上的任何事物之间都会存在一定联系,"城门失火,殃及池鱼"就是一个很好的例子.因此如果我们能够尽早发现这些看不见的联系,就能很好的解决更多遇见的 ...
- linux中wc命令
目录 一:linux中wc命令 1.wc命令介绍 2.wc命令作用 3.wc命令格式 4.参数 5.解析案例 一:linux中wc命令 1.wc命令介绍 Linux wc命令用于计算字数. 利用wc指 ...
- ApacheCN 所有教程/文档集已备份到 Coding
QuantLearning 数据科学 WIKI 安全 WIKI 团队 WIKI Sklearn 中文文档 PyTorch 中文文档 TutorialsPoint 中文系列教程 Java8 中文官方教程 ...
- rm, git rm, git rm --cached 区别与关系
HEAD, staging area, working copy在上篇<Git命令之回退篇 git revert git reset>已经讲过,不明白请自行传送过去. 1. rm 是仅仅删 ...
- 学习jsp篇:jsp Cookie介绍
这篇博客介绍下Cookie,JSP中比较重要的知识点Session,Cookie,表单数据,过滤器,文件上传.而Session和Cookie一般放在一起讲,在介绍cookie之前,要先介绍下Cooki ...
- Java程序性能监控工具
系统性能监控: 确定系统运行的整体状态,基本定位问题所在 uptime命令 [root@localhost ~]# uptime23:19:38 up 244 days, 3:39, 34 users ...