我可以将异步放在C#的顶层(服务层)吗?

时间:2016-07-05 13:38:23

标签: c# .net asynchronous async-await

我有一个分层架构,通常在顶级服务层放置try / catches,logging和async之类的东西,这样我的域代码和存储库就会同步编写,然后我用await任务将调用包装在服务层中.run所以我可以将Async命名和逻辑保存在一个层中。这个可以吗?或者是否有理由在所有子方法/较低层中同步?它实际上会产生更多的线程,还是只有1个异步线程来完成魔术?

如果没有这个问题,我有一个问题,在我的存储库中我需要使用HttpClient但它只有异步方法迫使我在我不想要的架构中使用async lower。有没有办法在没有await / async的情况下调用这些方法,然后在更高层的方法(在我的服务层中)仍然包装在task.run中而不会阻塞?基本上我不希望任何方法在我的存储库中异步,而是希望它们在我的服务层中,这会调用存储库和其他域方法。

1 个答案:

答案 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个异步线程可以实现魔术?

There is no thread.

我建议您阅读best practices

Stephen Toub附加阅读。