如果要在调用层次结构中深入实现异步方法,最佳做法(或最佳建议的做法)是使所有父对象同步吗?
我完全理解控制流如何在异步方法中移动,但是互联网上的大多数示例只显示了一种方法。我感兴趣的是如何在深度嵌套的调用层次结构中使用async / await。
例如,如果您有以下情况会发生什么:
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.
}
这似乎主要是因为你想在一个深度嵌套的子方法中异步获取Products,所有的父方法现在必须标记为异步(我没有在上面的例子中将父节点标记为async,用于此示例)
这是正确的假设吗?
现在,我知道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基本“封装”到一个方法中的一种方法。但是在很多文章/教程中,这是不受欢迎的(并且背后有有效但尚未理解的技术解释)
所以更一般地总结一下这个问题:当你在一个方法上使用async / await时,你的整个父调用者层次结构,从调用你的方法的直接父类开始,一直到root方法(你的调用者没有控制权) over),实现为异步方法?
经验法则是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.
}
如果可能的话,尝试使root方法异步也很重要。 ASP.NET MVC支持异步操作。如果您正在编写控制台应用程序而您正在使用C#7,那么您也可以使Main
方法异步。