根据文档 a ValueTask<TResult>..。
提供一个值类型,该值类型包装
Task<TResult>和TResult,仅使用其中一种。
我的问题是C#编译器在遇到async关键字时生成的状态机。当结果立即可用时,生成一个包装一个TResult的TResult,还是在一个await之后生成一个包装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。我担心状态机总是返回Task包装器,否定了ValueTask类型相对于Task的所有优点(并保留了所有的缺点)。据我所知,ValueTask<TResult>类型的属性没有说明它在内部包装了什么。我将上面的代码粘贴到sharplab.io,但是输出也没有帮助我回答这个问题。
发布于 2019-08-23 16:15:29
我想我应该回答我自己的问题,因为我现在知道答案了。答案是,我的担忧是没有道理的:-- C#编译器非常聪明,在每种情况下都能发出正确的ValueTask<TResult>类型。当结果同步可用时,它会发出一个值包装器,而如果不是,则会发出一个任务包装器。
我通过性能度量得出了这个结论:通过测量在每种情况下分配的内存,以及创建相同数量的任务所需的时间。结果是明确和一致的。例如,当一个ValueTask<int>包装一个int值时,它要消耗整整12个字节,当它包装一个Task<int>时,它要消耗精确的48个字节,所以毫无疑问,它下面发生了什么事情。
发布于 2019-08-10 15:36:57
编译器蠢到可以做它被告知的事情:
https://source.dot.net/#System.Private.CoreLib/shared/System/Threading/Tasks/ValueTask.cs,409
[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder<>))]
[StructLayout(LayoutKind.Auto)]
public readonly struct ValueTask<TResult> : IEquatable<ValueTask<TResult>>小心使用ValueTask
https://stackoverflow.com/questions/57440047
复制相似问题