ASP.NET(MVC)Outputcache和并发请求

时间:2010-01-29 14:15:18

标签: asp.net asp.net-mvc outputcache

让我们说,理论上,我在我的网站上有一个页面/控制器动作,它做了一些非常重的事情。完成它的操作大约需要10秒钟。

现在,我使用.NET的outputcache机制将其缓存15分钟(例如,我使用[OutputCache(Duration = 900)])如果在15分钟后缓存过期并且100个用户再次请求页面,会发生什么?进行重处理需要10秒钟?

  1. 重要的东西只在第一次完成,并且有一些锁定机制,以便其他99个用户将获得缓存结果
  2. 沉重的东西已经完成了100次(服务器已经瘫痪,因为它可能需要100 * 10秒)。
  3. 简单的问题可能,但我不是百分百肯定。我希望它是第一,但是: - )

    谢谢!

5 个答案:

答案 0 :(得分:4)

嗯,这取决于你如何配置IIS。如果你的工作线程少于100个(假设是50个),那么“重物”就会完成50次,使你的服务器瘫痪,剩下的50个请求将从缓存中提供。

但不,缓存的操作结果没有“锁定机制”;在大多数情况下,这会适得其反。

编辑:我认为这是真的,但尼克的测试说不然,我现在没有时间进行测试。亲自尝试一下!其余的答案并不依赖于上述情况,我认为这更重要。

但是,一般来说,没有Web请求,缓存或其他方式,都需要10秒才能返回。如果我在你的鞋子里,我会以某种方式预先计算请求的难点部分。如果要缓存HTML,您仍然可以缓存操作结果,但听起来您的问题比这更大。

可能也想要consider asynchronous controllers。最后,请注意,尽管IIS和ASP.NET MVC不会锁定这种繁重的计算,但您可以。如果您使用异步控制器并结合锁定计算,那么您将有效地获得您要求的行为。如果不了解更多关于你做什么的话,我不能说这是最好的解决方案。

答案 1 :(得分:3)

它似乎在这里锁定,做了一个简单的测试:

<%@ OutputCache Duration="10" VaryByParam="*" %>

protected void Page_Load(object sender, EventArgs e)
{
    System.Threading.Thread.Sleep(new Random().Next(1000, 30000));
}

第一页在那里遇到一个断点,即使它处于休眠状态......没有其他请求在Page_Load方法中遇到断点...它等待第一个断点完成并将结果返回给所有请求的人页。

注意:在webforms方案中测试更简单,但鉴于这是框架的共享方面,您可以在MVC中执行相同的测试,结果相同。

以下是另一种测试方法:

<asp:Literal ID="litCount" runat="server" />

public static int Count = 0;

protected void Page_Load(object sender, EventArgs e)
{
  litCount.Text = Count++.ToString();
  System.Threading.Thread.Sleep(10000);
}

第一个请求进入休眠状态时排队的所有页面将具有相同的计数输出。

答案 2 :(得分:3)

老问题,但我遇到了这个问题,并做了一些调查。

示例代码:

public static int Count;
[OutputCache(Duration = 20, VaryByParam = "*")]
public ActionResult Test()
{
    var i = Int32.MaxValue;
    System.Threading.Thread.Sleep(4000);
    return Content(Count++);
}

在一个浏览器中运行它,似乎锁定并等待。

在不同的浏览器中运行它(我在IE和Firefox中测试过),请求不会被搁置。

因此,“正确”行为更多地与您使用的浏览器相比,而不是IIS中的功能。

编辑:澄清 - 没有锁定。在缓存第一个结果之前,服务器会遇到所有设置进入的请求,这可能会导致服务器受到严重打击。 (或者,如果您呼叫外部系统,如果您的服务器提供许多请求,则该系统可能会被关闭......)

答案 3 :(得分:1)

我做了一个可能有帮助的小测试。我相信我发现的是未缓存的请求不会阻塞,并且在缓存过期时和任务完成之前进入的每个请求都会触发该任务。

例如,使用Cassini,我的系统下面的代码大约需要6-9秒。如果您发送两个请求,大约相隔2秒(即两个浏览器选项卡),两者都将收到唯一的结果。最后一个完成请求也是为后续请求缓存的响应。

// CachedController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace HttpCacheTest.Controllers
{
    public class CachedController : Controller
    {
        //
        // GET: /Cached/

        [OutputCache(Duration=20, VaryByParam="*")]
        public ActionResult Index()
        {
            var start = DateTime.Now;

            var i = Int32.MaxValue;
            while (i > 0)
            {
                i--;
            }
            var end = DateTime.Now;

            return Content( end.Subtract(start).ToString() );
        }

    }
}

答案 4 :(得分:0)

您应该查看此信息here: &#34;您有一个客户端向服务器发出多个并发请求。默认行为是这些请求将被序列化;&#34;

因此,如果来自单个客户端的并发请求被序列化,则后续请求将使用缓存。这解释了上面的一些答案(@ mats-nilsson和@ nick-craver)

您向我们展示的上下文是多个用户,它们会在同一时间点击您的服务器,并且您的服务器将忙碌,直到完成至少一个请求并创建输出缓存,并将其用于下一个请求。因此,如果要序列化请求相同资源的多个用户,我们需要了解序列化请求对单个用户的工作原理。这就是你想要的吗?