概要

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>的更多相关文章

  1. 【C# Task】理解Task中的ConfigureAwait配置同步上下文

    原文:https://devblogs.microsoft.com/dotnet/configureawait-faq/ 作者:Stephen 翻译:xiaoxiaotank 静下心来,你一定会有收获 ...

  2. 【SRM-06 D】五色战队&&【codeforces 788E】 New task

    原题链接:788E - New task Description 游行寺家里人们的发色多种多样,有基佬紫.原谅绿.少女粉.高级黑.相簿白等. 日向彼方:吾令人观其气,气成五彩,此天子气也. 琉璃:我们 ...

  3. 【ZOJ 3844】Easy Task

    题意 每次把序列中最大的数a的一个和最小的数b的一个变成a-b.求最后是否能使序列里的数全部相同,能则输出这个相同的数. 分析 一定是有解的,不断减少最大数的个数,最大数减少为0个时,就是减少了不同数 ...

  4. 【C# Task】开篇

    概览 在学task类之前必须学习线程的知识. 以下是task命名空间的类的结构图 1.2种任务类型: 有返回值task<TResult> .无返回值task. 2.2座任务工厂 TaskF ...

  5. 【.NET+MQTT】.NET6 环境下实现MQTT通信,以及服务端、客户端的双边消息订阅与发布的代码演示

    前言: MQTT广泛应用于工业物联网.智能家居.各类智能制造或各类自动化场景等.MQTT是一个基于客户端-服务器的消息发布/订阅传输协议,在很多受限的环境下,比如说机器与机器通信.机器与物联网通信等. ...

  6. 反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑) C#中缓存的使用 C#操作redis WPF 控件库——可拖动选项卡的TabControl 【Bootstrap系列】详解Bootstrap-table AutoFac event 和delegate的分别 常见的异步方式async 和 await C# Task用法 c#源码的执行过程

    反爬虫:利用ASP.NET MVC的Filter和缓存(入坑出坑)   背景介绍: 为了平衡社区成员的贡献和索取,一起帮引入了帮帮币.当用户积分(帮帮点)达到一定数额之后,就会“掉落”一定数量的“帮帮 ...

  7. 【30.93%】【codeforces 558E】A Simple Task

    time limit per test5 seconds memory limit per test512 megabytes inputstandard input outputstandard o ...

  8. 【EWM系列】SAP EWM创建warehouse task的函数

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP EWM创建warehouse ...

  9. 【C# task】TaskContinuationOptions 位枚举

    TaskContinuationOptions 根据 TaskContinuationOptions 的不同,出现了三个分支 LongRunning:独立线程,和线程池无关 包含 PreferFair ...

随机推荐

  1. 【小记录】android命令行程序发生coredump后读取堆栈信息

    一开始执行: adb shell cd /data/local/tmp ulimit -c unlimited ./xxx 然后查看coredump文件信息: adb pull /data/local ...

  2. 乡亲们,我们创建了 Dapr 中文交流频道

    我们创建了 Dapr 中文交流 QQ 频道,欢迎大家加入!加入方式在文章最后一节. 为什么要创建频道? 解决什么问题 专业性,"你可以在我们群里面钓鱼,因为都是水" 你肯定加过非常 ...

  3. 实习之bii--源码安装bind9

    刚学习linux时安装过fctix小企鹅输入法,那个比这个安装还要复杂,不过在这里也写一写,还是用的./configure make makeinstall这套命令.不像fctix有些高版本开始用cm ...

  4. 3D建模服务提供更高效、专业的能力,“筑”力开发者

    3D建模服务(3D Modeling Kit)是HMS Core在图形图像领域又一技术开放.3D建模产品的定位就是要做快速.简洁.低成本的3D制作能力,并陆续开放给有3D模型.动画游戏制作等能力诉求的 ...

  5. 『无为则无心』Python函数 — 35、Python中的闭包

    目录 1.闭包的概念 2.实现一个闭包 3.在闭包中外函数把临时变量绑定给内函数 4.闭包中内函数修改外函数局部变量 5.注意: 6.练习: 1.闭包的概念 请大家跟我理解一下,如果在一个函数的内部定 ...

  6. 前端HTML基础之form表单

    目录 一:form表单 1.form表单功能 2.表单元素 二:form表单搭建(注册页面) 1.编写input会出现黄色阴影问题 三:完整版,前端代码(注册页面) 四:type属性介绍 1.inpu ...

  7. Pycharm 使用备忘

    1.打开方法定义 快捷方式:[ctrl+左键]或者[Ctrl+B] 如果点击之后,打开不是[.py]文件,而是[.pyi]文件,可以把下面红框的参数删掉. 2.设置文件开头默认注释 # *_* cod ...

  8. iBooker AI+财务提升星球 2020.4 热门讨论

    比特币量化套利的心路历程(附python量化招聘)(分享自知- 如何选择一份好的工作? 你知道为什么大家都想去好公司吗? 不- #财务知识# 可转债套利 辉丰转债128012套利之三个知道- #财务知 ...

  9. [免费下载应用]iNeuKernel.Ocr 图像数据识别与采集原理和产品化应用

    目       录 1..... 应用概述... 2 2..... 免费下载试用... 2 3..... 视频介绍... 2 4..... iNeuLink.Ocr图像数据采集应用... 2 5... ...

  10. Mysql Json函数之更新 (四)

    修改JSON值的函数 本节中的函数将修改JSON值并返回结果. JSON_APPEND(json_doc, path, val[, path, val] ...) 将值附加到JSON文档中指定数组的末 ...