9

假设从理论上讲,我的网站中有一个页面/控制器操作,它做了一些非常繁重的事情。完成它的操作大约需要 10 秒。

现在,我使用 .NET 的 outputcache 机制将其缓存 15 分钟(例如,我使用[OutputCache(Duration = 900)])如果 15 分钟后缓存过期并且 100 个用户在执行重加工?

  1. 繁重的东西只做第一次,有一些锁定机制,让其他99个用户得到缓存结果
  2. 繁重的工作完成了 100 次(服务器瘫痪,因为它可能需要 100 * 10 秒)

可能是简单的问题,但我不是 100% 确定。不过,我希望它是第一名:-)

谢谢!

4

5 回答 5

4

好吧,这取决于您如何配置 IIS。如果您的工作线程少于 100 个(比如说 50 个),那么“繁重的工作”会执行 50 次,从而削弱您的服务器,然后将从缓存中提供剩余的 50 个请求。

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

编辑:我相信这是真的,但尼克的测试不是这样,我现在没有时间测试。自己试试吧!不过,其余的答案并不依赖于上述内容,我认为这更重要。

然而,一般来说,没有任何 Web 请求,无论是缓存的还是其他的,都应该需要 10 秒才能返回。如果我站在你的立场上,我会以某种方式预先计算请求的困难部分。如果要缓存 HTML,您仍然可以缓存操作结果,但听起来您的问题比这要大一些。

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

于 2010-01-29T14:26:38.390 回答
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);
}

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

于 2010-01-29T14:31:52.867 回答
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 中的功能有关。

编辑:澄清 - 没有锁。在缓存第一个结果之前,所有设法进入的请求都会攻击服务器,这可能会导致服务器因大量请求而受到重创。(或者,如果您调用外部系统,如果您的服务器处理许多请求,该系统可能会被关闭......)

于 2012-12-11T11:46:42.737 回答
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() );
        }

    }
}
于 2011-05-24T20:42:01.197 回答
0

您应该在此处检查此信息:“您有一个客户端向服务器发出多个并发请求。默认行为是这些请求将被序列化;”

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

您向我们展示的上下文是多个用户,它们将同时访问您的服务器,并且您的服务器将变得忙碌,直到完成至少一个请求并创建输出缓存,并将其用于下一个请求。所以如果你想序列化请求相同资源的多个用户,我们需要了解序列化请求是如何为单个用户工作的。那是你要的吗?

于 2016-01-21T13:04:49.543 回答