为什么 Task<T> 比 ValueTask<T> 更快?

5

我正在对 Task<T>ValueTask<T> 进行基准测试。以下是源代码:

#LINQPad optimize+     // Enable compiler optimizations

void Main()
{
    Util.AutoScrollResults = true;
    BenchmarkRunner.Run<TaskAndValueTaskComparsion>();
}

[ShortRunJob]
public class TaskAndValueTaskComparsion
{
    [Benchmark]
    public ValueTask<int> RunValueTaskWithNew()
    {
        return new ValueTask<int>(1);
    }
    
    [Benchmark]
    public Task<int> RunTaskFromResult()
    {
        return Task.FromResult(1);
    }
}

enter image description here

对于结果而言,Task<T>ValueTask<T> 快得多。但是为什么呢?我真的期望在返回任务对象时 ValueTask<T> 会造成更少的分配。

7
我猜这是因为Task.FromResult(1)被缓存了,而且同一个引用一直从你的方法中返回。 - haim770
4
Task.FromResult<T>() 会缓存某些常用的值,例如 truefalse01 等等。以下是实现的一些链接:https://github.com/dotnet/runtime/blob/486b4d1a36aef5bbe6a77bb2c3412772e712961e/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs#L5219-L5272 https://github.com/dotnet/runtime/blob/486b4d1a36aef5bbe6a77bb2c3412772e712961e/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/TaskCache.cs#L10 - Martin Costello
5
你的代码每次都明确地分配了一个新的ValueTask。它甚至不是相同的API。请至少使用ValueTask.FromResult - Panagiotis Kanavos
1
Task.FromResult 在可能的情况下会缓存任务,特别是对于值类型。 - Panagiotis Kanavos
3
我尝试了65534作为值。 ValueTask <T> 确实快了一点。 新结果在这里:https://user-images.githubusercontent.com/88981/170971437-cb2d33f9-8211-42d8-b619-0433af649c36.png - Will Huang
显示剩余2条评论
1个回答

6
感谢所有评论者。让我们总结一下所有这些有价值的信息。
在.NET运行时中有一个 TaskCache.cs,为各种原始类型的值创建可缓存的Task,如true(bool),false(bool),-1~9(int)。Task.FromResult 利用了这些缓存的 Task。
因此,基准测试结果是不正确的,因为 Task.FromResult 总是返回缓存版本的 Task 对象,而 new ValueTask<int>(1) 总是返回新值。
欲了解更多信息,请参阅Understanding the Whys, Whats, and Whens of ValueTask
如果您能读中文,我昨天也写了一篇文章。请看这里

new ValueTask<int>(1)总是返回一个新的对象实例。”-- 值类型通常被描述为“对象”罕见。这种描述通常保留给引用类型。 - Theodor Zoulias
@TheodorZoulias 你可以用什么“术语”代替“对象”? - Will Huang
@TheodorZoulias 我修改了我的句子,只需从中删除“object”即可。感谢您的评论。 - Will Huang
1
我的偏好是“始终返回新值”。据我所知,“实例”这个术语也与引用类型相关联。例如,int i = 1,人们通常不会说他们创建了一个新的int实例。 - Theodor Zoulias

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接