Task FromResult vs TaskCompletionSource SetResult

Posted

技术标签:

【中文标题】Task FromResult vs TaskCompletionSource SetResult【英文标题】: 【发布时间】:2014-02-10 22:16:09 【问题描述】:

关于的功能和意义有什么区别

TaskCompletionSource + SetResult vs Task + FromResult

在 SendAsync 方法中?

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

    if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
    
        var response = new HttpResponseMessage(HttpStatusCode.Forbidden) ReasonPhrase = "HTTPS Required";
        var taskCompletionSource = new TaskCompletionSource<HttpResponseMessage>();
        taskCompletionSource.SetResult(response);
        return taskCompletionSource.Task;
    
    return base.SendAsync(request, cancellationToken);


protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

    if (!request.RequestUri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
    
        HttpResponseMessage reply = request.CreateErrorResponse(HttpStatusCode.BadRequest, "HTTPS is required for security reason.");
        return Task.FromResult(reply);
    

    return base.SendAsync(request, cancellationToken);

【问题讨论】:

【参考方案1】:

Task.FromResult 是 .NET 4.5 中的新增功能。它是创建 TaskCompletionSource 并调用 SetResult 的辅助方法。如果您使用的是 .NET 4 或更早版本,则必须使用 SetResult。

【讨论】:

您提到的“.Net 4.5 中的新插件”使它成为我没有人提及的解决方案。 Task.FromResult 不使用TaskCompletionSourceTask.FromResult 调用特殊的内部构造函数来创建一个已经完成的任务。 From source code comments. @Fabio 感谢您的澄清。我可能从 MS 看到了一些 shim 代码,它们伪造了向后兼容的方法,并假设它是这样工作的。 @Miller 请更新您的答案以包括 Fabio 的澄清。【参考方案2】:

如果您只想返回一个完整的 Task&lt;TResult&gt; 并返回一个结果(或一个完整的 Task 没有结果),只需使用 Task.FromResult

Task.FromResult 是一个简单的工具,用于创建已完成的任务并获得结果。 TaskCompletionSource 是一个更强大的工具,支持一切。您可以设置异常、返回未完成的任务并稍后设置结果等等

P.S:您似乎正试图通过返回已完成的任务来“伪造”异步方法。尽管这是最好的方法,但请确保“伪造”异步确实是您想要完成的。

【讨论】:

【参考方案3】:

我很确定Task.FromResult() 在幕后做了非常相似的事情。

TaskCompletionSource 的更好用例场景是您自己实现多线程。在这种情况下,您会立即返回一个等待的任务,直到后台线程完成并调用TaskCompletionSource.SetResult()TaskCompletionSource.SetException() 后才会设置其结果。

【讨论】:

【参考方案4】:

我相信Task.FromResult() 效率更高,但您也可以执行以下操作,IMO 更具可读性:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)

    if (request.RequestUri.Scheme != Uri.UriSchemeHttps)
        return new HttpResponseMessage(HttpStatusCode.Forbidden) ReasonPhrase = "HTTPS Required";
    return await base.SendAsync(request, cancellationToken);

您仍然可以覆盖基的虚拟SendAsync,因为async 不会更改方法签名。

【讨论】:

【参考方案5】:

Task.FromResult 是为同步方法创建任务的便捷方法。尽管 Task 表示异步操作,但并非所有 Task 实际上都是异步的,并且可能只是同步方法的简单包装。

如果您使用 Task.FromResult,那么请在您的文档中说明您的方法不是“真正的”异步方法,而是语法糖块。这将通知调用者不要期望它的异步行为。

另一方面,如果您想手动创建异步函数,请使用 TaskCompletionSource 的SetResult 或TrySetResult 方法,如here 所述。

无论您的 .NET 框架的版本如何,始终使用 TaskCompletionSource 而不是 Task.FromResult 来创建真正的异步函数。

来源:

    Task.FromResult Internal Constructor of Task TaskCompletionSource.SetResult TaskCompletionSource.TrySetResult

【讨论】:

以上是关于Task FromResult vs TaskCompletionSource SetResult的主要内容,如果未能解决你的问题,请参考以下文章

我应该使用 Task.Run 还是 Task.FromResult?

C# 中 Task.FromResult<TResult> 的用途是啥

c#—— Task.FromResult 的使用

对于代表返回 void 的操作的任务,Task.FromResult<T>() 的替代方法是啥?

FromResult方法

使用ServiceLoader辅助责任链模式