在深度嵌套的方法层次结构中异步/等待

时间:2018-09-03 15:51:55

标签: c# asynchronous async-await

如果要在调用层次结构的深处实现异步方法,最佳实践(或最佳建议实践)是使所有父级异步吗?

我完全理解了控制流如何以异步方法移动,但是Internet上的大多数示例仅显示了一种方法。我对如何在深度嵌套的调用层次结构中使用异步/等待感兴趣。

例如,如果您有以下情况会发生什么:

void ControllerMethod() // Root method
{
     ServiceA_MethodOne();
}

// In another place in code
void ServiceA_MethodOne() 
{
     ServiceB_MethodOne();
}

// In another place in code
async Task<List<Product>> ServiceB_MethodOne()
{
     var data = await ctx.Products.ToListAsync();
     // some code here works with data.
}

看来,本质上是因为您想在深层嵌套子方法之一中异步获取产品,所以现在所有父方法都必须标记为异步(在上面的示例中,我没有将父方法标记为异步)。例子)

这是正确的假设吗?

现在,我了解GetAwaiter().GetResult(),实际上可以做到这一点:

void ControllerMethod() // Root method
{
     ServiceA_MethodOne();
}

// In another place in code
void ServiceA_MethodOne() 
{
     ServiceB_MethodOne().GetAwaiter().GetResult();
}

// In another place in code
async Task<List<Product>> ServiceB_MethodOne()
{
     var data = await ctx.Products.ToListAsync();
     // some code here works with data.
}

这是将异步基本“封装”为一种方法的一种方法。但是在很多文章/教程中,人们对此并不满意(并且背后有有效但尚未理解的技术解释)

因此,更笼统地概括这个问题:当您在方法上使用async / await时,您的整个父级调用者层次结构是否都从调用方法的直接父级开始,一直到根方法(您的调用者无法控制),可以实现为异步方法?

1 个答案:

答案 0 :(得分:2)

经验法则是async all the way。这不一定意味着您需要使用async关键字。您也可以返回已收到的相同任务。

void ControllerMethod() // Root method
{
     return ServiceA_MethodOne().GetAwaiter().GetResult();
}

// In another place in code
Task ServiceA_MethodOne() 
{
     return ServiceB_MethodOne();
}

// In another place in code
async Task<List<Product>> ServiceB_MethodOne()
{
     var data = await ctx.Products.ToListAsync();
     // some code here works with data.
}

如果可能的话,使根方法异步也是很重要的。 ASP.NET MVC支持异步操作。如果您正在编写控制台应用程序,并且正在使用C#7,则还可以使Main方法异步。