使Controller方法异步或保持同步?

时间:2016-06-13 17:05:55

标签: c# asp.net-mvc asynchronous

我正在使用预先存在的C#ASP.NET MVC webapplication,我正在添加一些功能,我无法决定是否进行异步。

现在,应用程序主页只处理一个页面,用户登录。没有更多,也没有任何异步。

我添加的功能将在访问主页时生成对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);

    }

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

这里,使用异步IO的原因是没有多个线程同时运行。线程消耗OS资源和内存。线程池也可能有点慢,以适应突然负载。如果你在网络应用程序中的线程数低于100并且加载不是非常混乱,你就不用担心了。

通常,Web服务越慢,它被称为更有利的异步IO就越频繁。您将需要平均(延迟*频率)线程运行。因此,100ms通话时间和每秒10次通话平均约为1个线程。

运行数字并查看是否需要更改任何内容。

答案 1 :(得分:1)

首先,在Web应用程序的上下文中实现异步的目的。 Web服务器具有所谓的线程池。一般来说,1个线程== 1个请求,因此如果池中有1000个线程(典型值),则您的网站可以大致同时提供1000个请求。还要记住,渲染单个资源通常需要很多请求。 HTML文档本身是一个请求,但每个图像,JS文件,CSS文件等也是一个请求。然后,页面可能会发出任何AJAX请求。换句话说,请求单个资源向Web服务器生成20多个请求的情况并不少见。

鉴于此,当您的服务器达到其最大请求(正在使用所有线程)时,任何进一步的请求都会排队并按顺序处理,因为线程可用。什么异步做的是给你一些额外的头部空间。如果存在处于等待状态的线程(等待数据库查询的结果,来自Web服务的响应,要从文件系统读取的文件等),则异步允许这些线程返回到池,然后他们可以在那里等待一些等待请求。当线程等待完成时,请求新线程完成请求的服务。

这里要注意的重要一点是请求新线程以完成对请求的服务。一旦线程被释放到池中,您就必须再次等待一个线程,就像一个全新的请求一样。这意味着运行async有时可以更长而不是运行同步,具体取决于池中线程的可用性。此外,异步龋齿带来了非显着的开销,这也增加了总体加载时间。

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

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

答案 2 :(得分:1)

  

有什么想法吗?

是的,很多想法......但仅凭这一点并不算作答案。 ;)

<小时/> 这里没有真正的好答案,因为没有提供太多的上下文。但是,让我们解决我们所知道的问题。

  1. 由于我们是一个Web应用程序,每个请求/响应周期都会对性能产生直接影响,并且可能成为瓶颈。
  2. 由于我们在内部调用我们的另一个API调用,我们不应该假设它托管在同一台服务器上 - 因此应该像所有I / O绑定操作一样对待它。
  3. 根据上述两个已知因素,我们应该拨打电话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>返回操作。这有助于确保理想的性能。请注意client.DownloadStringAsync上的API更改,这非常重要。