在 Task.Run() 中包装同步调用以使其异步有益吗?

Posted

技术标签:

【中文标题】在 Task.Run() 中包装同步调用以使其异步有益吗?【英文标题】:Is wrapping a synchronous call in a Task.Run() to make it asynchronous beneficial? 【发布时间】:2012-10-15 19:52:36 【问题描述】:

我提出这个问题的动机是因为我正在创建一个 .net Web API 项目,该项目将使用具有同步方法的现有 neo4j rest api 客户端。我想通过使用异步方法来利用一些性能提升,但我想避免进入 neo4j api 库并重构同步方法以返回异步方法。我想知道是否将对同步方法的调用包装在 await Task.Run() 中是否有益。具体来说,在第一个示例中,当来自 httpClient 的异步结果调用 Wait() 方法时会发生什么,但整个事情都包装在另一个 await 中。

另外请记住,我将在 AppHarbor 云上使用我认为是单个虚拟内核的东西运行它。

下面也是这样

  //what happens with the synchronous rest api client I am using
  HttpResponseMessage SendHttpRequest(HttpRequestMessage request)
  

        var requestTask = httpClient.SendAsync(request);
        requestTask.Wait();
        return requestTask.Result;

  

  object result = await Task.Run(() =>
  
      return SendHttpRequest(request);
  );

性能与

相似
 return httpClient.SendAsync(request)

【问题讨论】:

【参考方案1】:

我想通过使用异步方法来利用一些性能提升,但我想避免进入 neo4j api 库并重构同步方法以返回异步方法。

抱歉,如果您只是将同步代码包装在 Task.Run 中,您将失去服务器端 async 的所有好处。

async 在服务器上很好,因为异步操作比线程更好地扩展。但是,如果您使用的是Task.Run,那么无论如何您都在使用线程。

【讨论】:

【参考方案2】:

不同之处在于 Task.Run 方法只是在线程池上运行相同的阻塞代码。这意味着虽然它不会阻塞你的调用线程,但它会阻塞执行线程。

这有多重要完全取决于资源和性能方面的考虑。

如果 SendHttpRequest 方法真的只是在等待 httpClient.SendAsync 任务,您可以简单地避免该方法并编写:

object result = await httpClient.SendAsync(request);

或者:

object result = await Task.Run(async () => await httpClient.SendAsync(request));

如果 SendAsync 任务仍应在单独的线程上运行。

【讨论】:

以上是关于在 Task.Run() 中包装同步调用以使其异步有益吗?的主要内容,如果未能解决你的问题,请参考以下文章

将异步委托传递给Task.Run? [复制]

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?

Task.Run 中的异步 lambda 与常规 lambda [重复]

task 异步

使用异步方法等待 Task.Run 不会在正确的线程上引发异常

Task.Run()方法总结