14

我在高流量场景中有一个多层 C# MVC4 Web 应用程序,它为各种存储库使用依赖注入。这非常有用,因为它易于测试,并且在生产中我们可以轻松地为特定控制器配置存储库。所有控制器都继承自 AsyncController,因此返回Task<JsonResult>Task<ActionResult>真正帮助我们的服务器扩展更多用户并解决可怕的线程饥饿问题的操作方法. 一些存储库使用 Web 服务,我们绝对可以使用 Async/Await 来提供可扩展性优势。在其他情况下,有些人可能使用无法安全线程化的非托管服务,其中 async/await 不会提供任何好处。每个存储库都是一个接口 IRepository 的实现。简而言之,每种实现在获取数据的方式上都大不相同。此配置是在部署时通过 web.config 更改和 Autofac 模块选择的。

在这样的应用程序中实现 async/await 的推荐方法有哪些?为了使模式适合我现有的应用程序,我必须将接口更改为 return Task<MyBusinessObject>但这不是更多的实现细节吗? 我可以提供两个方法存根GetDataGetDataAsync,但对我来说,这不允许我现在使用 Autofac 等 IoC 框架所拥有的灵活性,我可以轻松地交换所有内容而无需更改代码。

Async/Await 的 Microsoft 开发人员之一发表了一篇博文,“我应该为我的同步方法公开一个异步包装器吗? ”这就是问题所在。如果您的异步方法不是真正的异步(提供本机 I/O 优势),那么它实际上只会增加开销。换句话说,它不会提供任何可扩展性优势。

我只是想知道社区的其他成员是如何解决这个问题的。

4

2 回答 2

15

在您的情况下,我建议使您的接口异步:

public interface IMyInterface
{
  Task<TMyResult> GetDataAsync();
}

对于同步方法,您可以返回Task.FromResult

public class MyImplementation : IMyInterface
{
  public Task<TMyResult> GetDataAsync()
  {
    TMyResult ret = ...;
    return Task.FromResult(ret);
  }
}

异步方法当然可以async和使用await

关于实施细节,我会说“是和不是”。;) 在这方面非常相似IDisposable。从逻辑上讲,它是一个实现细节,因为它的实现方式无关紧要。在调用代码需要以不同方式处理它的意义上,这不是一个实现细节。所以我同意 - 从逻辑上讲 - 这是一个实现细节,但 .NET 平台还不够先进,无法如此对待它。

或者,您可以这样想(这是我通常给出的解释):async是实际的实现细节,当您返回Task<T>而不是 时T,您正在定义一个实现可能是异步的接口。

我有一系列博客文章解决了async“大规模”的设计问题(即,async与 OOP 相适应,而不是让它发挥作用)。我解决了一些常见问题,例如异步初始化和 IoC。这只是一个人的意见,但我不知道有任何其他资源可以解决这类问题。

PS 你不再需要AsyncController在 MVC4 中继承。async默认控制器处理程序将通过返回类型(TaskTask<T>)自动检测方法。

于 2013-05-21T20:01:41.770 回答
2

任务是一个泄漏的抽象。如果您希望受益于 IO 完成端口线程的使用,您必须将任务从您的存储库一路返回到您的控制器。

尽管返回整个调用堆栈Task<T>可能会提高可伸缩性,但它确实为您的应用程序增加了一层额外的复杂性。这将阻碍可维护性、可测试性,并使推理代码变得更加困难。异步代码总是比同步代码更难

就个人而言,我宁愿增加服务器的内存量并将应用程序配置为具有更大的线程池以补偿可伸缩性的损失,或者横向扩展到一些额外的(虚拟)服务器,而不是增加这种额外的复杂性。

于 2013-05-21T19:40:08.170 回答