异步等待调用长时间运行的同步和异步方法

8

我将使用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);
}

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

在我的更改之后,对远程服务的调用采用了async-await方式,该服务再次调用数据库。

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

即使第二个调用没有使用async-await方式,我对远程database_service的调用仍有好处吗?还有什么可以改进的地方吗?

注意

我问这个问题的原因是:

"使用异步控制器时,当一个进程正在等待I/O完成时,其线程被释放以供服务器用于处理其他请求。"

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

但是第二个标签计算需要1.5秒钟,这将再次阻塞当前线程1.5秒钟?

所以我释放和阻塞线程,这没有意义,你认为呢?


当你使用async时,不需要使用Task.FromResult,只需使用return label;。你的第一个示例中是否意味着不使用async/await - Scott Chamberlain
我知道... 因此我给你呈现了“修改后的代码”,这就是你现在建议的内容。 - Pascal
3个回答

2
渲染库不仅仅是“阻塞线程”,它正在执行渲染工作。你无法做得更好。

请回答我的第一个问题:“我用异步等待的方式进行了远程数据库服务调用,但第二次调用没有这样做,是否仍然有好处?”谢谢 :-) - Pascal
在这两个示例中,您都是使用async await方式调用远程方法。我在评论中向您提出了这一点。由于第一个代码无法编译,因此我无法说它与另一个代码相比如何,因为第一个代码无法运行。 - Scott Chamberlain
因此,我写了“伪代码”,所以它无法编译。是的,我在第一个示例中并不是指等待(await)。那只是一个复制/粘贴错误。我已经纠正了它。 - Pascal
1
在这种情况下,只对第一次调用使用async-await是有好处的,在等待数据库响应的1秒钟内,服务器可以处理另一个传入请求。这将增加服务器支持的最大并发请求数量。 - Scott Chamberlain

1
异步代码在后台创建了一定的连续性,这是一种合成糖来使异步编程感觉更加同步。
通常情况下,根据操作本身的不同,将长时间运行的任务都设置为异步可能会有所帮助。它将在幕后使用不同的任务来处理每个不同的长时间运行任务并以异步方式运行它们。
目前,在GetProductLabel中完全同步地运行这些任务,这意味着如果它是您唯一调用的方法,则无法区分同步代码。
如果可能的话,我会将第二个方法设置为异步,因为我不熟悉使用任务和异步等待的任何重大缺点。
在您的情况下,您无法做得更好,并且没有太大的区别,因为您必须按同步方式运行它,因为您正在使用第一个方法的结果。

1

我使用异步等待的方式进行了远程database_service调用,但第二个调用没有。这样做还有好处吗?

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

还有什么可以改进的吗?

如果您也可以将第二个调用异步运行,整个方法就可以异步运行,并且不会阻塞。


现在的非阻塞调用会在那1秒钟内将线程返回给调用者,以便IIS可以将另一个HTTP请求放到该线程上吗?还是只有当方法调用完全异步等待时,线程才会返回给调用者? - Pascal
它将返回那1秒钟的线程。可以这样想:所有非异步语句都会阻塞当前线程,即使像var s =“Hello,World。”这样的语句也是如此,只是发生得太快了,不要紧。许多异步方法都有类似的语句,但这并不妨碍它们利用异步的好处。您的第二个阻塞调用行为相同---它不会阻止其他异步调用异步工作,只是需要很长时间。 - Bradley Moorfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接