多层C#应用程序中的异步/等待
在高流量场景中,我有一个多层C#MVC4 web应用程序,它对各种存储库使用依赖注入。这非常有用,因为它易于测试,并且在生产中,我们可以轻松地为特定控制器配置存储库。所有控制器都继承自AsyncController,因此返回多层C#应用程序中的异步/等待,c#,interface,repository-pattern,async-await,C#,Interface,Repository Pattern,Async Await,在高流量场景中,我有一个多层C#MVC4 web应用程序,它对各种存储库使用依赖注入。这非常有用,因为它易于测试,并且在生产中,我们可以轻松地为特定控制器配置存储库。所有控制器都继承自AsyncController,因此返回Task或Task的操作方法。有些存储库使用web服务,我们完全可以使用Async/Await来提供可伸缩性优势。在其他情况下,有些可能使用无法安全线程化的非托管服务,在这种情况下,async/await不会提供任何好处。每个存储库都是一个接口IRepository的实现。简
Task
或Task的操作方法。有些存储库使用web服务,我们完全可以使用Async/Await来提供可伸缩性优势。在其他情况下,有些可能使用无法安全线程化的非托管服务,在这种情况下,async/await不会提供任何好处。每个存储库都是一个接口IRepository的实现。简而言之,每个实现在获取数据的方式上都有很大的不同。此配置在部署时随web.config更改和Autofac模块一起选择
在这样的应用程序中实现异步/等待的推荐方法有哪些?为了使模式适合我现有的应用程序,我必须更改接口以返回Task
但这不是一个更详细的实现细节吗?我可以提供两个方法存根,GetData
和GetDataAsync
,但对我来说,这不允许像Autofac这样的IoC框架具有灵活性,我可以轻松地交换所有内容,而无需更改代码
一位Microsoft Async/Await的开发人员发表了一篇博客文章,“类似这样的问题。如果您的异步方法不是真正的异步(提供本机I/O好处),那么它实际上只会增加开销。换句话说,它不会提供任何可伸缩性好处
我只想知道社区的其他成员是如何解决这个问题的。任务是一个漏洞百出的抽象概念。如果您希望从IO完成端口线程的使用中获益,则必须将任务从存储库一直返回到控制器
尽管使整个调用堆栈返回任务
可能会提高可伸缩性,但它确实会给应用程序增加一层额外的复杂性。这将阻碍可维护性、可测试性,并使对代码进行推理变得更加困难
就我个人而言,我宁愿增加服务器的内存量,并将应用程序配置为具有更大的线程池以补偿可扩展性的损失,或者扩展到几个额外的(虚拟)服务器,而不是增加这种额外的复杂性。在您的情况下,我建议将接口设置为异步:
public interface IMyInterface
{
Task<TMyResult> GetDataAsync();
}
异步方法当然可以是async
和wait
关于实施细节,我会说“是和否”。)在这方面,它与IDisposable
非常相似。从逻辑上讲,这是一个实现细节,从这个意义上讲,它不应该在意以何种方式实现。这不是一个实现细节,因为调用代码需要以不同的方式处理它。因此,从逻辑上讲,我同意这是一个实现细节,但是.NET平台还没有足够的先进性来处理它
或者,您可以这样想(这是我通常给出的解释):async
是实际的实现细节,当您返回Task
而不是T
时,您定义了一个接口,其中的实现可能是异步的
我有一个解决方案,就是“在大范围内”使用async
进行设计(即,将async
与OOP配合使用,而不是允许它发挥功能)。我将解决一些常见问题,如异步初始化和IoC。这只是一个人的意见,但我不知道有什么其他资源可以解决这类问题
另外,在MVC4中,您不再需要从
AsyncController
继承。默认控制器处理程序将根据返回类型(Task
或Task
)自动检测async
方法。async
和wait
只是将阻塞方法转换为非阻塞方法的抽象。您可以在代码中的任何位置执行此操作,而无需更改接口,除非您希望强制接口方法始终是异步的。如果您在整个调用堆栈中没有任务,则它将永远不会被异步调用。所以你必须把它放在接口中,才能始终返回任务。我不是这么说的。我说的是,通过使用async
和await
可以将任何方法转换为异步方法,包括接口上已有的任何阻塞方法。原始方法上不需要任务
返回类型。当然,用它们的async
等价物替换所有接口方法是完全有效的,但这不是必需的。这没有任何好处,实际上增加了开销。查看Stephen Toub关于它的博客文章“我应该为我的同步方法公开一个异步包装器吗?”@CyanLite:如果在整个调用堆栈中不使用Task,代码可以异步工作,但在这种情况下,您将无法从IO完成端口线程中获益,这在你的情况下似乎很关键。我不同意额外的复杂性。使用async
/await
(一旦您理解了它们),可维护性、可测试性和代码推理都非常简单。指向您的一系列博客文章的链接似乎已断开。你能更新吗?没关系,Chrome很愚蠢,没有正确地“翻译”链接。谢谢你的发帖。事实上,链接断了;今年早些时候我换了供应商。现在修好了,谢谢!啊,很高兴我提到了什么。好东西,顺便说一句。谢谢你发表博客文章。然而,当涉及到调用异步方法和使用注入对象时,我找不到关于DI/IoC使用的更多信息(不幸的是,注释长度限制不能让我更具体)
public class MyImplementation : IMyInterface
{
public Task<TMyResult> GetDataAsync()
{
TMyResult ret = ...;
return Task.FromResult(ret);
}
}