我有一个分层架构,通常在顶级服务层放置try / catches,logging和async之类的东西,这样我的域代码和存储库就会同步编写,然后我用await任务将调用包装在服务层中.run所以我可以将Async命名和逻辑保存在一个层中。这个可以吗?或者是否有理由在所有子方法/较低层中同步?它实际上会产生更多的线程,还是只有1个异步线程来完成魔术?
如果没有这个问题,我有一个问题,在我的存储库中我需要使用HttpClient但它只有异步方法迫使我在我不想要的架构中使用async lower。有没有办法在没有await / async的情况下调用这些方法,然后在更高层的方法(在我的服务层中)仍然包装在task.run中而不会阻塞?基本上我不希望任何方法在我的存储库中异步,而是希望它们在我的服务层中,这会调用存储库和其他域方法。
答案 0 :(得分:3)
这样可以吗?
不,not ok。
根据Stephen Cleary撰写的一篇非常精彩的博客文章:
一旦(至少)引入了四个效率问题 在ASP.NET中使用await与Task.Run:
- 额外(不必要的)线程切换到Task.Run线程池 线。同样,当该线程完成请求时,它必须 输入请求上下文(不是实际的线程切换但是 确实有开销)。
- 创建额外(不必要的)垃圾。 异步编程是一种权衡:你会增加 以更高的内存使用为代价的响应性。在这种情况下, 最终会为异步操作创建更多垃圾 完全没必要。
- 抛出ASP.NET线程池启发式 通过Task.Run“意外地”借用线程池线程。我不 在这里有很多经验,但我的直觉告诉我那个 如果意外任务真的很短,启发式应该可以很好地恢复 如果意外的任务持续更多,并且不会优雅地处理它 超过两秒钟。
- ASP.NET无法提前终止请求, 即,如果客户端断开连接或请求超时。在里面 同步的情况下,ASP.NET知道请求线程并可以中止它。 在异步的情况下,ASP.NET不知道辅助 线程池线程是“for”该请求。有可能解决这个问题 通过使用取消令牌,但这超出了此范围 博客文章。
这应该是足以警告重新考虑你的方法。 "您使用Task.Run
进行异步包装的事实是一种代码味道"
是否有理由在所有子方法/较低层中都有
async
?
是的,etiquette。
它实际上会产生更多的线程,还是只有1个异步线程可以实现魔术?
我建议您阅读best practices。
Stephen Toub附加阅读。