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

C# 深度嵌套方法层次结构中的异步/等待,c#,asynchronous,async-await,C#,Asynchronous,Async Await,如果您想在调用层次结构的深处实现一个异步方法,那么最好的做法(或建议的最佳做法)是使所有父级都异步吗 我完全理解控制流在异步方法中是如何移动的,但internet上的大多数示例只显示了一种方法。我对如何在深度嵌套的调用层次结构中使用async/Wait感兴趣 例如,如果您有: void ControllerMethod() // Root method { ServiceA_MethodOne(); } // In another place in code void Service

如果您想在调用层次结构的深处实现一个异步方法,那么最好的做法(或建议的最佳做法)是使所有父级都异步吗

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

例如,如果您有:

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.
}
这将是一种基本上将异步“封装”到一个方法中的方法。但在很多文章/教程中,这一点都是不受欢迎的(其背后有一些有效但尚未理解的技术解释)

因此,更笼统地总结一下这个问题:当您对一个方法使用async/Wait时,您的整个父调用方层次结构(从调用您的方法的直接父调用方开始,一直到根方法(您无法控制其调用方)是否都实现为异步方法?

经验法则是这样的。这并不一定意味着您需要使用
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.
}
void ControllerMethod()//根方法
{
返回ServiceA_MethodOne().GetAwaiter().GetResult();
}
//在代码的另一个地方
任务服务a_MethodOne()
{
返回ServiceB_MethodOne();
}
//在代码的另一个地方
异步任务服务B_MethodOne()
{
var data=await ctx.Products.ToListAsync();
//这里的一些代码处理数据。
}

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

您可能需要进行阅读,因为这是一个类似但不同的问题。因此,假设我正在设计服务方法,我需要异步和非异步方法。在不重复逻辑的情况下,实现这一点最高效的方法是什么?是否应该有ServiceB_MethodOne()和ServiceB_MethodOneAsync()只运行Task.Run(()=>ServiceB_MethodOne())?不,要使async工作,或者至少有一些实用程序,您需要一直执行async,如果没有,就像@hardkoded所说的,如果需要从sync方法调用async,则必须使用.getwaiter().GetResult();,这使得异步useless@rekiem87:我不认为使用GetAwaiter().GetResult()会使异步变得毫无用处。如果需要并行加载三种模型的数据:产品、用户和客户,该怎么办?为什么不能在父方法上使用Task.WaitAll(getProductsTask、getUsersTask、GetCustomerTask)然后使用GetAwaiter().GetResult()异步加载它们?可以使用GetAwaiter().GetResult()。corefx中有一些示例,您不应该使用Task.Run模拟同步方法的异步,因为这将浪费线程池线程或导致线程拥塞,如果您多次这样做,这可能会成为一个问题。使用
Task.FromResult(ServiceB_MethodOne)
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.
}