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
不使用TaskCompletionSource
。 Task.FromResult
调用特殊的内部构造函数来创建一个已经完成的任务。 From source code comments.
@Fabio 感谢您的澄清。我可能从 MS 看到了一些 shim 代码,它们伪造了向后兼容的方法,并假设它是这样工作的。
@Miller 请更新您的答案以包括 Fabio 的澄清。【参考方案2】:
如果您只想返回一个完整的 Task<TResult>
并返回一个结果(或一个完整的 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> 的用途是啥