【问题标题】:async await calling long running sync AND async methods异步等待调用长时间运行的同步和异步方法
【发布时间】:2016-07-25 05:40:12
【问题描述】:

我正在使用 asp.net web api 2 和 Entity Framework 6。

原始伪代码

public IHttpActionResult GetProductLabel(int productId)
{
      var productDetails = repository.GetProductDetails(productId); 
      var label = labelCalculator.Render(productDetails);  
      return Ok(label);
}

修改后的代码

public async Task<IHttpActionResult> GetProductLabel(int productId)
{
      var productDetails = await repository.GetProductDetailsAsync(productId); // 1 long second as this call goes into sub services
      var label = labelCalculator.Render(productDetails); // 1.5 seconds synchrounous code
      return Ok(label);
}

在我进行更改之前,一切都是同步运行的。

在我更改对远程服务的调用后,该服务再次调用数据库以异步等待方式完成。

然后我对只提供同步方法的渲染库进行同步调用。计算需要 1.5 秒。

远程 database_service 调用 async-await 方式但第 2 次调用没有,还有什么好处吗?还有什么我可以改进的吗?

注意

之所以这么问是因为:

“使用异步控制器,当进程等待 I/O 完成时,它的线程被释放,供服务器用于处理其他请求。”

所以当第一个远程 database_service 调用正在处理并等待那 1 秒时,线程返回到 IIS??!!

但是第二个标签计算需要 1.5 秒会再次阻塞当前线程 1.5 秒吗?

所以我释放并阻塞线程,这没有意义或者你怎么看?

【问题讨论】:

  • 当你有async 时你不使用Task.FromResult,只使用return label; 你的意思是在你的第一个例子中不使用async/await 吗?
  • 我知道...因此我向您展示了“修改后的代码”,这就是您现在的建议。

标签: c# asp.net asynchronous async-await asp.net-web-api2


【解决方案1】:

渲染库不只是“阻塞线程”,它正在执行您的渲染工作。没有比这更好的了。

【讨论】:

  • 还请解决我的第一个问题:“我以异步等待方式调用远程 database_service 但第二次调用没有,这还有什么好处吗?”谢谢:-)
  • 在这两个示例中,您都将远程方法称为异步等待方式。我在评论中向您提出了这一点。您的第一个代码甚至无法编译,所以我不能说它会如何比较,因为第一个代码无法运行。
  • 因此我写了“伪代码”所以它无法编译。是的,我并不是说在我的第一个样本中等待。那是一个复制/粘贴错字。我现在更正了。
  • 在这种情况下,只对第一个调用执行 async-await 是有好处的,在这 1 秒钟内,您正在等待数据库响应,服务器可以处理另一个传入请求。这将增加您的服务器可以支持的最大并发请求数。
【解决方案2】:

我进行远程 database_service 调用还有什么好处吗 异步等待方式,但第二次调用不是?

是的,这个调用现在是非阻塞的,并且可以与其他代码一起运行,即使它只有 1 秒。

还有什么我可以改进的吗?

如果你也可以让第二个调用异步运行,整个方法可以异步运行,根本不会阻塞。

【讨论】:

  • 现在的非阻塞调用是否会在那 1 秒内将线程返回给调用者,以便 IIS 可以在该线程上放置另一个 http 请求?还是只有在方法调用一直是 async-await 时才返回给调用者的线程?
  • 它将返回那 1 秒的线程。可以这样想:all 非异步语句阻塞了当前线程——甚至像var s = "Hello, World." 这样的东西——它发生得太快了,没关系。许多异步方法都有这样的语句,但这并不能阻止它们利用异步的好处。您的第二个阻塞调用的行为相同——它不会阻止其他异步调用异步工作,只是需要很长时间。
【解决方案3】:

异步代码在底层创建了某种延续,它是一种合成糖,让异步编程感觉更同步。

一般来说,取决于操作本身,它可能有助于使两个长时间运行的任务异步。它将在后台为每个不同的长时间运行的任务使用不同的任务并异步运行它们。

目前,这些任务在 GetProductLabel 中完全同步运行,这意味着如果它是您调用的唯一方法,您将无法区分同步代码之间的区别。

如果可能的话,我会让第二种方法异步,因为我不熟悉使用任务和异步等待的任何明显缺点。

在您的情况下,没有什么比这更好的了,而且不会有太大的不同,因为您必须同步运行它,因为您使用的是第一种方法的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多