首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用AsyncController帮助提高遗留ASP.NET MVC 3项目的并发性

使用AsyncController帮助提高遗留ASP.NET MVC 3项目的并发性
EN

Stack Overflow用户
提问于 2013-10-11 20:49:17
回答 5查看 705关注 0票数 1

我们有一个网站,目前正在与并发用户进行斗争。

以下是该项目的高层次背景:

  • 遗留的ASP.NET MVC 3项目(.NET 4)
  • 不能对核心代码进行任何主要重写
  • 执行时间最长的主要入口点是SubmitSearch控制器上的Search操作。平均响应时间为5-10秒。

因此,正如第二点所概述的,我们不想花太多的时间在这个项目上重写大的部分。但是,我们希望尝试增加并发用户。我们不打算改变任何其他东西或提高性能,因为这将需要更多的工作。

我们所看到的是,随着越来越多的人访问SubmitSearch,网站总体上会放缓。这很可能是因为所有IIS线程都被锁定,执行搜索。

我们希望实现AsyncController,并使SubmitSearch操作在普通CLR线程上执行。下面是我们想要实现的方法:

假设这是原始的SubmitSearch方法:

代码语言:javascript
复制
/// <summary>
/// Submits a search for execution.
/// </summary>
/// <param name="searchData">The search data</param>
/// <returns></returns>
public virtual ActionResult SubmitSearch(SearchFormModel searchData)
{
    //our search code
}

我们希望转换为AsyncController的最快方法是简单地这样做:

代码语言:javascript
复制
/// <summary>
/// Submits a search for execution.
/// </summary>
/// <param name="searchData">The search data</param>
/// <returns></returns>
protected virtual ActionResult SubmitSearch(SearchFormModel searchData)
{
    //our search code
}

/// <summary>
/// Asynchronous Search entry point
/// </summary>
/// <param name="searchData"></param>
public void SubmitSearchAsync(SearchFormModel searchData)
{
    AsyncManager.OutstandingOperations.Increment();
    System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
        ActionResult result = SubmitSearch(searchData);
        AsyncManager.Parameters["result"] = result;
        AsyncManager.OutstandingOperations.Decrement();
    });

    return;
}

/// <summary>
/// Called when the asynchronous search has completed
/// </summary>
/// <param name="result"></param>
/// <returns></returns>
public ActionResult SubmitSearchCompleted(ActionResult result)
{
    //Just return the action result
    return result;
}

当然,这不起作用,因为贯穿整个代码,我们引用的是HttpContext.Current,在这种方法中,我们知道它最终是null

所以我们希望用SubmitSearchAsync来做这件事

代码语言:javascript
复制
/// <summary>
/// Asynchronous Search entry point
/// </summary>
/// <param name="searchData"></param>
public void SubmitSearchAsync(SearchFormModel searchData)
{
    AsyncManager.OutstandingOperations.Increment();
    System.Threading.Tasks.Task.Factory.StartNew(() =>
    {
        ActionResult result = null;
        AsyncManager.Sync(() =>
        {
            result = SubmitSearch(searchData);
        });

        AsyncManager.Parameters["result"] = result;
        AsyncManager.OutstandingOperations.Decrement();
    });

    return;
}

这解决了这个问题。

所以我担心的是:

SubmitSearch方法中包装AsyncManager.Sync的执行是否辜负了使用该模型的目的?换句话说,当我们在AsyncManager.Sync方法中时,我们是否回到了IIS线程,这使我们回到了第一步?

谢谢

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-11-09 03:33:16

SubmitSearch方法中包装AsyncManager.Sync的执行是否辜负了使用该模型的目的?换句话说,当我们在AsyncManager.Sync方法中时,我们是否回到了IIS线程,这使我们回到了第一步?

或多或少,是的。但不幸的是,在您的示例中,使用Task.Factory.StartNew 也使无法使用异步控制器。用你想要的方法,你赢不了。

IIS线程(由ThreadPool.QueueUserWorkItem启动的线程和Task线程)都来自同一个线程池。

为了从异步控制器中获得任何好处,您需要真正的异步方法。换句话说,像Stream.ReadAsyncWebRequest.GetResponseAsync这样的方法。这些特别命名的方法使用I/O完成端口而不是普通线程,后者使用硬件中断并在不同的线程池上操作。

很久以前,我在这里的回答中提到了这一点:在高流量情况下在ThreadPool.QueueUserWorkItem中使用ASP.NET。任务和服务生是非常贴心的,但它们不会改变.NET线程池的基本动态。

需要注意的一件事是,有一个选项,TaskCreationOptions.LongRunning,您可以在创建Task时指定它,这实际上告诉框架任务将做大量等待,理论上,TPL将试图避免在线程池中调度它。实际上,这在高流量站点上可能不太实用,因为:

  1. 该框架实际上并不保证它不会使用线程池。这是一个实现细节,该选项只是您提供的一个提示。
  2. 即使它确实避免了池,它仍然需要使用线程,这在本质上就像使用new Thread --如果不是字面意义上的,那么至少是有效的。这意味着大量的上下文切换,这绝对会降低性能,也是线程池首先存在的主要原因。

"search“命令显然意味着某种I/O,这意味着您可能可以在某个地方使用真正的异步方法,即使它是旧风格的BeginXyz/EndXyz。这里没有快捷方式,也没有快速修复;您必须重新构建代码才能真正实现异步的。

.NET框架无法检查Task内部发生了什么,并神奇地将其转换为中断。它不能使用I/O完成端口,除非直接引用知道它们的特定方法。

接下来,您使用的web或中间件应用程序,试着提前考虑这一点,避免像瘟疫一样的同步I/O。

票数 6
EN

Stack Overflow用户

发布于 2013-11-09 04:49:13

我认为,到目前为止,阿罗瑞格有着最好的答案:你需要真正的异步处理来进行扩展(例如,Begin/End,而不仅仅是使用线程池线程),而且异步代码没有快捷方式或快速修复--至少需要对该部分进行重新设计。

这让我想到你问题的这一部分:

我们不想花太多的时间在这个项目重写大的部分。

最好的好处可能是购买更多的内存,并把它放在服务器上。(您应该先检查分析器,以确保它是内存问题-内存通常是ASP.NET的限制因素,但最好先检查一下)。

虽然我们开发人员喜欢解决问题,但事实是,我们可以消耗大量时间,例如,将同步代码转换为异步代码。FYI,基于任务的异步模式(async/await)在.NET 4.5中将允许您更容易地将同步代码更改为异步代码。

所以现在,我说买几个内存芯片,然后在你切换到async 4.5之后,做一个思想上的笔记,把它升级到.NET上(容易得多)。

票数 2
EN

Stack Overflow用户

发布于 2013-11-07 05:51:22

首先,我将查看服务器本身的性能,然后考虑使用visual中的分析工具来准确地确定瓶颈所在。考虑查看迷你分析器,其中的讨论可以在这里找到http://www.hanselman.com/blog/NuGetPackageOfTheWeek9ASPNETMiniProfilerFromStackExchangeRocksYourWorld.aspx。一般同意上面关于线程消耗的评论。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19327011

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档