我使用IO的所有操作都应该是异步的吗?

时间:2014-04-22 18:07:22

标签: c# io task-parallel-library async-await asp.net-mvc-5

当我阅读MSDN文章 Using Asynchronous Methods in ASP.NET MVC 4 时,我得出的结论是,我应该始终使用异步等待来进行I / O绑定操作。

考虑以下代码,其中movieManager公开ORM的异步方法,如Entity Framework。

public class MovieController : Controller
{
    // fields and constructors

    public async Task<ActionResult> Index()
    {
        var movies = await movieManager.listAsync();

        return View(movies);
    }

    public async Task<ActionResult> Details(int id)
    {
        var movie = await movieManager.FindAsync(id);

        return View(movie);
    }
}
  1. 这总能给我带来更好的可扩展性和/或性能吗?
    • 我该如何衡量?
  2. 为什么不在&#34;现实世界中使用?&#34;?
  3. 上下文同步怎么样?
    • 是不是很糟糕,我不应该在ASP.NET MVC中使用异步I / O?
  4. 我知道这些问题很多,但关于这个主题的文献却有相互矛盾的结论。有人说你应该总是对依赖于I / O的任务使用异步,其他人说你根本不应该在ASP.NET应用程序中使用async。

3 个答案:

答案 0 :(得分:24)

  

这总能给我带来更好的可扩展性和/或性能吗?

可能。如果您只有一个数据库服务器作为后端,那么您的数据库可能是您的可扩展性瓶颈,在这种情况下,扩展您的Web服务器不会对整个服务范围产生任何影响。

  

我该如何衡量?

进行负载测试。如果您想要一个简单的概念验证,可以查看this gist of mine

  

为什么不在现实世界中使用这个&#34;很多?

是的。 .NET 4.5之前的异步请求处理程序编写起来非常痛苦,很多公司只是在这个问题上投入了更多的硬件。现在.NET 4.5和async / await正在获得很大动力,异步请求处理将继续变得更加普遍。

  

上下文同步怎么样?

ASP.NET为您处理了这个问题。我的博客上有async intro,其中说明await在您SynchronizationContext任务时如何捕获当前await。在这种情况下,AspNetSynchronizationContext表示请求,因此HttpContext.Current,文化等所有内容都会自动保存在await个点。

  

是不是很糟糕,我不应该在ASP.NET MVC中使用异步I / O?

作为一般规则,如果您使用的是.NET 4.5,则应使用async来处理任何需要I / O的请求。如果请求很简单(即没有访问数据库或调用其他服务),那么只需保持同步即可。

答案 1 :(得分:2)

  

这总能给我带来更好的可扩展性和/或性能吗?

你自己回答,你需要测量并找出答案。通常,async是稍后要添加的,因为增加了复杂性,这是代码库中的第一个问题,直到您遇到特定问题。

  

我该如何衡量?

以两种方式构建它,看哪个更快(最好是大量操作)

  

为什么不在现实世界中使用这个&#34;很多?

因为复杂性是软件开发中的最大问题。如果代码很复杂,则更容易出错并且更难调试。更多,更难以修复错误不是一个很好的权衡性能优势。

  

上下文同步怎么样?

我假设您的意思是ASP.NET上下文,如果是这样,您不应该进行任何同步,请确保只有一个线程可以访问您的上下文并通过它进行通信。

  

是不是很糟糕,我不应该在ASP.NET MVC中使用异步I / O?

除非你真的需要性能,否则引入异步只是为了处理同步是一种损失。

答案 2 :(得分:-1)

将异步代码放在网站上有很多不利的方面:

  • 当数据之间存在依赖关系时,您会遇到麻烦,因为您无法使其异步。
  • 异步工作通常用于API请求之类的事情。您是否认为不应该在网页中进行这些操作?如果外部服务出现故障,您的网站也会出现故障。这不会扩展。
  • 异步处理可能会在某些情况下加速您的网站,但您基本上会引入麻烦。你总是等待最慢的一个,因为有时资源只是因为某种原因而变慢,这意味着减慢你网站速度的风险会增加一个等于你正在使用的异步工作数量的因素。你必须引入超时来处理这些,然后是错误处理代码等。
  • 当因为CPU负载过重而扩展到多个Web服务器时,异步工作会对您造成伤害。以前用于放入异步代码的所有内容现在在用户单击链接的同时触发,然后缓解。这不仅适用于CPU负载,还适用于数据库负载甚至API请求。您将在所有系统资源中看到非常糟糕的利用率模式:大量使用的峰值,然后再次下降。这不能很好地扩展。同步代码没有这个问题:作业只在另一个完成后才开始。

网站的异步工作是一个陷阱:不要去那里!

将重型代码放在工作人员(或cron作业)中,在用户提出要求之前执行这些操作。您可以将它们放在数据库中,并且可以继续为站点添加功能,而不必担心会触发太多异步作业,而不必担心。

网站的效果严重受到高估。当然,如果您的页面在50ms内呈现,那就太好了,但是如果它需要250ms,那么人们真的不会注意到(测试一下:在代码中添加Sleep(200))。

如果您只是将工作卸载到另一个进程并使网站只是您的数据库的接口,那么您的代码将变得更具可伸缩性。不要让你的网络服务器做繁重的工作,它不应该做,它不会扩展。你可以让一百台机器每个网页共花费1个CPU小时 - 但至少它会以200ms内仍然加载的方式进行扩展。祝你用异步代码实现这一目标。


我想在此添加旁注。虽然我对异步代码的看法似乎很强,但它主要是对程序员的看法。异步代码很棒,可以产生性能差异,证明我概述的所有要点都是错误的。但是,它需要在代码中进行大量微调以避免我在本文中提到的观点,并且大多数程序员都无法处理。