.NET 4.6 的 Task.CompletedTask 有啥意义?

Posted

技术标签:

【中文标题】.NET 4.6 的 Task.CompletedTask 有啥意义?【英文标题】:What is the point of .NET 4.6's Task.CompletedTask?.NET 4.6 的 Task.CompletedTask 有什么意义? 【发布时间】:2015-08-10 03:54:51 【问题描述】:

This blog post 提到了新的任务 API,包括 .NET 4.6 中引入的新 Task.CompletedTask 属性。

为什么要添加这个?这比Task.FromResult(whatever) 好多少?

【问题讨论】:

意图更清晰还不够吗? 原因是您可以通过创建处于固定状态的静态不可变任务来节省内存。如果您需要返回已完成的任务,例如您只能选择从网上下载东西,否则返回一个设置为已完成的虚拟任务,以便等待您的任务的调用者可以立即继续。到目前为止,您需要创建自己的实例并缓存它,或者每次都通过 TaskCompletionSource 再次创建它。 博客文章已经解释了为什么添加Task.CompletedTask...它特别提到了“关心性能和避免分配的库代码”。现在将其与您的Task.FromResult(whatever) 进行比较:这是否避免了分配?不,它没有。 【参考方案1】:

Task.FromResult(whatever) 适用于 Task<TResult>,但在 4.6 之前,非通用任务没有任何内容。您可以将FromResult 与一个虚拟值一起使用并隐式将其转换为Task,但这有点混淆了意图(您实际上并没有返回任何异步)并在下面分配对象(而@ 987654325@可以被缓存并在所有调用者之间共享)。

在当前(4.5.2 及更早版本)代码库中看到自定义静态已完成任务并不少见,因此我认为将其合并到框架本身是有意义的。

【讨论】:

【参考方案2】:

Task.CompletedTask 属性在您需要给调用者一个已经完成的虚拟任务(不返回值/结果)时很重要。 这可能是履行“接口”合同或测试目的所必需的。

Task.FromResult(data) 也返回一个虚拟任务,但这次返回的是数据或结果。您可能会这样做,因为您已经拥有数据并且 无需执行任何操作即可获取。

使用示例

public Task DoSomethingAsync()

    return Task.CompletedTask; // null would throw exception on await


public Task<User> GetUserAsync()

    if(cachedUser != null) 
    
        return Task.FromResult(cachedUser);
    
    else
    
        return GetUserFromDb();
    

【讨论】:

以上是关于.NET 4.6 的 Task.CompletedTask 有啥意义?的主要内容,如果未能解决你的问题,请参考以下文章

已安装 4.6 时如何满足 .Net Framework 4.0 要求

.NET 4.6 的 Task.CompletedTask 有啥意义?

Visual Studio 2013 和 .NET 4.6

.NET 4.6 中的 OpenIddict 3 不可用令牌验证

使用 .NET 4.6 和 ASP.NET Core 的 TFS 2017 构建定义

从 .NET Framework 4.6 迁移到 .NET5 后,API 帖子正文为空