如果要在调用层次结构的深处实现异步方法,最佳实践(或最佳建议实践)是使所有父级异步吗?
我完全理解了控制流如何以异步方法移动,但是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时,您的整个父级调用者层次结构是否都从调用方法的直接父级开始,一直到根方法(您的调用者无法控制),可以实现为异步方法?
答案 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
方法异步。