【问题标题】:Task FromResult vs TaskCompletionSource SetResultTask 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);
}

【问题讨论】:

    标签: c# asp.net-web-api task-parallel-library async-await taskcompletionsource


    【解决方案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 的SetResultTrySetResult 方法,如here 所述。

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

          来源:

          1. Task.FromResult
          2. Internal Constructor of Task
          3. TaskCompletionSource.SetResult
          4. TaskCompletionSource.TrySetResult

          【讨论】:

            猜你喜欢
            • 2012-08-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多