多层c#应用中的Async/Await
本文关键字:Async Await 应用 多层 | 更新日期: 2023-09-27 18:14:54
我在一个高流量场景中有一个多层c# MVC4 web应用程序,它对各种存储库使用依赖注入。这是非常有用的,因为它很容易测试,并且在生产中,我们可以很容易地为特定的控制器配置存储库。所有的控制器都继承自AsyncController,所以返回Task<JsonResult>
或Task<ActionResult>
的action方法真正帮助我们的服务器扩展更多的用户,并解决了可怕的线程饥饿问题。一些存储库使用web服务,我们绝对可以使用Async/Await来提供可伸缩性优势。在其他情况下,有些人可能会使用不能安全地线程化的非托管服务,在这种情况下,async/await不会提供任何好处。每个存储库都是接口IRepository的实现。简而言之,每种实现在获取数据的方式上都有很大的不同。此配置是在web部署时选择的。配置更改和Autofac模块。
在这样的应用程序中实现async/await的推荐方法是什么?为了使模式适合我现有的应用程序,我必须更改接口以返回Task<MyBusinessObject>
。但是这不是一个实现细节吗?我可以提供两个方法桩,GetData
和GetDataAsync
,但对我来说,这将不允许我现在与像Autofac这样的IoC框架的灵活性,在那里我可以轻松地交换一切,而无需更改代码。
一个微软的Async/Await开发者发表了一篇博客文章,"我应该为我的同步方法公开一个异步包装器吗?"如果您的异步方法不是真正的异步(提供本机I/O优势),那么它实际上只会增加开销。换句话说,它不会提供任何可伸缩性优势。
我只是想知道社区其他成员是如何解决这个问题的。
在您的情况下,我建议您使用异步接口:
public interface IMyInterface
{
Task<TMyResult> GetDataAsync();
}
对于同步方法,可以返回Task.FromResult
:
public class MyImplementation : IMyInterface
{
public Task<TMyResult> GetDataAsync()
{
TMyResult ret = ...;
return Task.FromResult(ret);
}
}
异步方法当然可以是async
,而使用await
。
关于实现细节,我会说"是"answers"不是"。,)在这方面,它与IDisposable
非常相似。从逻辑上讲,它是一个实现细节,因为它与实现的方式无关。在调用代码需要以不同的方式处理它的意义上,它是而不是实现细节。因此,我同意——从逻辑上讲——这是一个实现细节,但是。net平台还不够先进,无法将其视为实现细节。
或者,您可以这样考虑(这是我通常给出的解释):async
是实际的实现细节,当您返回Task<T>
而不是T
时,您定义了一个接口,其中实现可以是异步的。
我有一系列的博客文章,讨论如何在大范围内设计async
(即,将async
与OOP相结合,而不是允许它具有功能)。我解决了一些常见的问题,如异步初始化和IoC。这只是一个人的意见,但我不知道有其他资源可以解决这类问题。
注:在MVC4中,您不再需要继承AsyncController
。默认控制器处理程序将根据返回类型(Task
或Task<T>
)自动检测async
方法。
任务是一个有漏洞的抽象。如果你希望受益于IO完成端口线程的使用,你将不得不从你的存储库一直返回到你的控制器。
虽然使整个调用堆栈返回Task<T>
可能会提高可伸缩性,但它确实为应用程序增加了额外的复杂性。这将阻碍可维护性、可测试性,并使代码推理变得更加困难。异步代码总是比同步代码更难。
就我个人而言,我宁愿增加服务器的内存量,并将应用程序配置为具有更大的线程池来补偿可伸缩性的损失,或者向外扩展到一些额外的(虚拟)服务器,而不是增加这种额外的复杂性。