ASP.NET Core EF Core场景下无需修改全调用链的异步方法使用问题
结论先行
没有既享受异步释放线程的收益、又不用修改上层调用链的方案,async/await的"传染性"是.NET的刻意设计,目的是让整个调用栈感知异步挂起逻辑,才能正确实现线程调度、上下文传递。
如果你硬要强行调用异步方法不修改上层签名(强烈不推荐)
可以用同步阻塞的写法,但是会完全失去异步操作的所有优势,还会带来额外风险:
- 直接调用
.Result或者.Wait()
代码示例:
风险:在带同步上下文的环境下会直接触发死锁,就算是无同步上下文的ASP.NET Core环境,也会一直占用调用线程等待IO完成,完全达不到你想要释放线程的目的,同时异常会被包装为public List<Person> GetPersons(string name) { // 其他逻辑 var list = dbContext.Persons.ToListAsync().Result; // 其他逻辑 return list; }AggregateException,排查难度提升。 - 调用
GetAwaiter().GetResult()
代码示例:
相比var list = dbContext.Persons.ToListAsync().GetAwaiter().GetResult();.Result的优势是异常不会额外包装,其余问题和上面完全一致。
推荐的正确方案
顺着编译器提示把整个调用链改为异步,实际改动量极小,是唯一能真正拿到异步性能收益的方案:
- 调整数据访问方法签名,加
async关键字,返回值改为Task<List<Person>>,建议方法名后缀加Async符合.NET编码约定:public async Task<List<Person>> GetPersonsAsync(string name) { // 此处有决定查询哪张表的逻辑 var list = await dbContext.Persons.ToListAsync(); // 此处还有针对"list"变量的更多内部逻辑 return list; } - 上层包装类的对应方法改为
async Task返回,await上述方法即可 - 最顶层的ASP.NET Core控制器原生支持异步动作方法,直接改为
async Task<IActionResult>返回即可,整个链路没有额外适配成本。
内容的提问来源于stack exchange,提问作者Tessaract
相关产品推荐
相关产品推荐

