c# - 价值任务和异步状态机
问题描述
根据文件ValueTask<TResult>
... _
提供包装 a
Task<TResult>
和 a的值类型TResult
,仅使用其中一个。
我的问题是关于 C# 编译器在async
遇到关键字时生成的状态机。当结果立即可用时,生成ValueTask<TResult>
包装 a 的a 是否足够聪明,或者当结果出现在 a 之后时生成包装 a ?这是一个例子:TResult
Task<TResult>
await
static async ValueTask<DateTime> GetNowAsync(bool withDelay)
{
if (withDelay) await Task.Delay(1000);
return DateTime.Now;
}
static void Test()
{
var t1 = GetNowAsync(false);
var t2 = GetNowAsync(true);
}
调用GetNowAsync(false)
应该返回一个TResult
包装器,因为没有等待,调用GetNowAsync(true)
应该返回一个Task<TResult>
包装器,因为Task.Delay
在结果可用之前等待 a。我担心状态机总是返回Task
包装器的可能性,从而抵消了该ValueTask
类型的所有优点Task
(并保留了所有缺点)。据我所知,该类型的属性ValueTask<TResult>
没有提供关于它内部包装的指示。我将上面的代码粘贴到了sharplab.io,但输出也没有帮助我回答这个问题。
解决方案
我想我应该回答我自己的问题,因为我现在知道答案了。答案是我的担心是多余的:C# 编译器足够聪明,ValueTask<TResult>
可以在每种情况下发出正确的类型。当结果同步可用时,它发出一个值包装器,当它不是时发出一个任务包装器。
我通过性能测量得出了这个结论:通过测量每种情况下分配的内存,以及创建相同数量的任务所需的时间。结果清晰且一致。例如, aValueTask<int>
包装一个值时恰好消耗 12 个字节,而包装a 时恰好消耗int
48 个字节Task<int>
,因此毫无疑问在幕后发生了什么。
推荐阅读
- r - 如何使用 writeMat 函数
- python - 烧瓶项目在 cython 中编译然后部署或运行
- angular - 在 Angular 中使用 markdown-parser
- asp.net-core - 防止在 Razor 页面中自动传递 URL 参数
- com - 将 BSTR 从 OLE 返回到 Inno Setup
- python - barplot中的索引和排序问题
- java - 警告 FXML 日食
- javascript - SignalR 仅在 azure 上偶尔发送消息
- node.js - Javascript异步函数正在等待响应而不等待
- node.js - 将数据库从 Firebase 转移到 Mongodb 问题?