2016-06-13 87 views
4

我正在使用预先存在的C#ASP.NET MVC web应用程序,并且我正在向它添加一些功能,我无法决定是否进行异步。使控制器方法异步或保持同步?

现在,应用程序主页只是处理页面并且用户登录。没有什么更多,也没有什么异步进行。

我添加的功能会在访问主页时生成对Web API的调用,该API随后会调用一个数据库来抓取标识符并将其返回给主页上的HTML标记。该标识符在屏幕上不可见,只能在源/ HTML视图(为了各种内部追踪目的而添加)中显示。

Web API /数据库调用很简单,只需抓住一个标识符并将其返回给控制器即可。无论如何,我想知道应用程序是否应该异步进行此调用?网站流量并不是很大,但我仍然想知道并发性,性能和未来的可伸缩性。

一个问题是,我必须使整个ActionMethod异步,我不知道这将是什么影响。基本模式,目前同步,如下:

public ActionResult Index() 
    { 
     var result = GetID(); 

     ViewBag.result = result.Data; 

     return View(); 
    } 

    public JsonResult GetID() 
    { 
     var result = ""; 
     var url = "http://APIURL/GetID"; 

     using (WebClient client = new WebClient()) 
     { 
      result = client.DownloadString(url); 
     } 

     return Json(result, JsonRequestBehavior.AllowGet); 

    } 

有什么想法?

+1

如果您可以使用async/await关键字,请始终使用async。如果您必须使用遗留模式,除非您遇到当前的扩展问题,否则请不要使用它 - 它会将复杂度提高到超出收益水平的程度。 – MatthewMartin

回答

2

这里,使用异步IO的原因是没有多个线程同时运行。线程消耗操作系统资源和内存。线程池也可能稍微缓慢以适应突发负载。如果您的网络应用程序的线程数低于100,并且负载不是非常尖锐,那么您无需担心。

一般来说,Web服务越慢,越经常被称为更有益的异步IO。您将需要平均(延迟*频率)线程运行。所以100ms的通话时间和每秒10次的通话量平均约为1个线程。

运行数字,看看你是否需要改变任何东西。

0

首先,在Web应用程序的上下文中实现异步的目的。 Web服务器具有所谓的线程池。一般来说,1个线程== 1请求,因此如果池中有1000个线程(典型),则您的网站可以大致提供1000个同时请求。同时请记住,它通常需要很多请求才能呈现单个资源。 HTML文档本身就是一个请求,但每个图像,JS文件,CSS文件等也是一个请求。然后,页面可能会发出任何AJAX请求。换句话说,请求单个资源向Web服务器生成20多个请求并不罕见。因为当你的服务器达到最大请求时(所有的线程都被使用),当线程可用时,任何进一步的请求都会按顺序排队和处理。异步的做法是给你一些额外的头部空间。如果线程处于等待状态(等待数据库查询的结果,来自Web服务的响应,从文件系统读取的文件等),那么异步允许这些线程返回到游泳池,然后他们可以在那里等待一些等待的请求。当线程等待完成时,请求一个新线程完成服务请求。

这里需要注意的一点是,新线程请求来完成服务请求。一旦线程被释放到池中,您必须再次等待线程,就像全新的请求一样。这意味着根据池中线程的可用性,运行异步有时可能会比运行同步更长。而且,异步龋齿带来的开销非常小,这也增加了总体加载时间。

异步!=更快。它可以多次是较慢的,但它允许您的Web服务器更有效地利用资源,这可能意味着下降和正常承载负载之间的差异。正因为如此,对于像“我应该让所有事情都异步吗?”这样的问题没有一个普遍的答案。异步是原始性能和效率之间的折衷。在某些情况下,根本无法使用异步,而在其他情况下,您可能想要将其用于适用的所有内容。你需要做的是首先确定应用程序的压力点。例如,如果你的数据库实例与你的Web服务器驻留在同一台服务器上(不是一个好主意,BTW),对数据库查询使用异步将毫无意义。等待的罪魁祸首是网络延迟,而文件系统访问通常相对较快。另一方面,如果您的数据库服务器位于远程数据中心,并且不仅需要在那里与您的Web服务器之间传输管道,还需要执行遍历防火墙等工作,那么您的网络延迟就更加重要,而异步可能是一个非常好的主意。

总而言之,您需要评估您的设置,您的环境和您的应用程序的需求。然后,只有那样,你能做出明智的决定。也就是说,即使考虑到异步的开销,如果涉及到网络延迟,也应该使用异步。在谨慎的网站上犯错并在适用的地方使用异步是完全可以接受的,许多人都这样做。如果你正在寻找性能优化(也许你开始下一个Facebook?),那么你会想要更明智。

1

有什么想法?

是的,很多的想法...但是这不能算作一个答案。 ;)


这里没有真正的好答案,因为没有提供很多上下文。但让我们解决我们所知道的。

  1. 由于我们是一个Web应用程序,每个请求/响应周期对性能有直接影响,可能是一个瓶颈。
  2. 由于我们在内部调用我们的另一个API调用,因此我们不应该假设它驻留在同一台服务器上 - 因此应该像处理所有I/O绑定操作一样对待它。

以上两个已知因素,我们应该拨打我们的电话async。考虑以下几点:

public async Task<ActionResult> Index() 
{ 
    var result = await GetIdAsync(); 

    ViewBag.result = result.Data; 

    return View(); 
} 

public async Task<JsonResult> GetIdAsync() 
{ 
    var result = ""; 
    var url = "http://APIURL/GetID"; 

    using (WebClient client = new WebClient()) 
    { 
     // Note the API change here? 
     result = await client.DownloadStringAsync(url); 
    } 

    return Json(result, JsonRequestBehavior.AllowGet); 
} 

现在,我们正在正确使用asyncawait关键字与我们Task<T>恢复操作。这将有助于确保理想的性能。请注意0​​上的API更改,这非常重要。