• ASP.NET: 缓存运用


    说到ASP.NET缓存,那就是:尽早缓存;经常缓存您应该在应用程序的每一层都实现缓存。向数据层、业务逻辑层、UI 或输出层添加缓存支持。内存现在非常便宜 — 因此,通过以智能的方式在整个应用程序中实现缓存,可以获得很大的性能提高。 缓存可以掩盖许多过失 缓存是一种无需大量时间和分析就可以获得“足够良好的”性能的方法。

    这里再次强调,内存现在非常便宜,因此,如果您能通过将输出缓存 30 秒,而不是花上一整天甚至一周的时间尝试优化代码或数据库就可以获得所需的性能,您肯定会选择缓存解决方案(假设可以接受 30 秒的旧数据)。缓存正是那些利用 20% 付出获得 80% 回报的特性之一,因此,要提高性能,应该首先想到缓存。

    不过,如果设计很糟糕,最终却有可能带来不良的后果,因此,您当然也应该尽量正确地设计应用程序。但如果您只是需要立即获得足够高的性能,缓存就是您的最佳选择,您可以在以后有时间的时候再尽快重新设计应用程序。 页面级输出缓存 作为最简单的缓存形式,输出缓存只是在内存中保留为响应请求而发送的 HTML 的副本。其后再有请求时将提供缓存的输出,直到缓存到期,这样,性能有可能得到很大的提高(取决于需要多少开销来创建原始页面输出 – 发送缓存的输出总是很快,并且比较稳定)。 实现 要实现页面输出缓存,只要将一条 OutputCache 指令添加到页面即可。

    ﹤%@ OutputCache Duration=”60″ VaryByParam=”*” %﹥

    如同其他页面指令一样,该指令应该出现在 ASPX 页面的顶部,即在任何输出之前。它支持五个属性(或参数),其中两个是必需的。  Duration 必需属性。页面应该被缓存的时间,以秒为单位。必须是正整数。Location 指定应该对输出进行缓存的位置。如果要指定该参数,则必须是下列选项之一:Any、Client、Downstream、None、Server 或 ServerAndClient。VaryByParam 必需属性。Request 中变量的名称,这些变量名应该产生单独的缓存条目。”none” 表示没有变动。”*” 可用于为每个不同的变量数组创建新的缓存条目。变量之间用 “; ” 进行分隔。 VaryByHeader 基于指定的标头中的变动改变缓存条目。

    VaryByCustom 允许在 global.asax 中指定自定义变动(例如,”Browser”)。 利用必需的 Duration 和 VaryByParam 选项的组合可以处理大多数情况。例如,如果您的产品目录允许用户基于 categoryID 和页变量查看目录页,您可以用参数值为 “categoryID; page” 的 VaryByParam 将产品目录缓存一段时间(如果产品不是随时都在改变,一小时还是可以接受的,因此,持续时间是 3600 秒)。这将为每个种类的每个目录页创建单独的缓存条目。每个条目从其第一个请求算起将维持一个小时。VaryByHeader 和 VaryByCustom 主要用于根据访问页面的客户端对页面的外观或内容进行自定义。同一个 URL 可能需要同时为浏览器和移动电话客户端呈现输出,因此,需要针对不同的客户端缓存不同的内容版本。

    或者,页面有可能已经针对 IE 进行了优化,但需要能针对 Netscape 或 Opera 完全降低优化(而不仅仅是破坏页面)。后一个例子非常普遍,我们将提供一个说明如何实现此目标的示例:示例:VaryByCustom 用于支持浏览器自定义 为了使每个浏览器都具有单独的缓存条目,VaryByCustom 的值可以设置为 “browser”。此功能已经内置在缓存模块中,并且将针对每个浏览器名称和主要版本插入单独的页面缓存版本。

    ﹤%@ OutputCache Duration=”60″ VaryByParam=”None” VaryByCustom=”browser” %﹥

    片段缓存,用户控件输出缓存 缓存整个页面通常并不可行,因为页面的某些部分是针对用户定制的。不过,页面的其他部分是整个应用程序共有的。这些部分最适合使用片段缓存和用户控件进行缓存。菜单和其他布局元素,尤其是那些从数据源动态生成的元素,也应该用这种方法进行缓存。如果需要,可以将缓存的控件配置为基于对其控件(或其他属性)的更改或由页面级输出缓存支持的任何其他变动进行改变。使用同一组控件的几百个页面还可以共享那些控件的缓存条目,而不是为每个页面保留单独的缓存版本。实现片段缓存使用的语法与页面级输出缓存一样,但其应用于用户控件(.ascx 文件)而不是 Web 窗体(.aspx 文件)。除了 Location 属性,对于 OutputCache 在 Web 窗体上支持的所有属性,用户控件也同样支持。用户控件还支持名为 VaryByControl 的 OutputCache 属性,该属性将根据用户控件(通常是页面上的控件,例如,DropDownList)的成员的值改变该控件的缓存。

    如果指定了 VaryByControl,可以省略 VaryByParam。最后,在默认情况下,对每个页面上的每个用户控件都单独进行缓存。不过,如果一个用户控件不随应用程序中的页面改变,并且在所有页面都使用相同的名称,则可以应用 Shared=”true” 参数,该参数将使用户控件的缓存版本供所有引用该控件的页面使用。 示例

    ﹤%@ OutputCache Duration=”60″ VaryByParam=”*” %﹥

    该示例将ASP.NET缓存用户控件 60 秒,并且将针对查询字符串的每个变动、针对此控件所在的每个页面创建单独的缓存条目。

    ﹤%@ OutputCache Duration=”60″ VaryByParam=”none” VaryByControl=”CategoryDropDownList” %﹥

    该示例将ASP.NET缓存用户控件 60 秒,并且将针对 CategoryDropDownList 控件的每个不同的值、针对此控件所在的每个页面创建单独的缓存条目。

    ﹤%@ OutputCache Duration=”60″ VaryByParam=”none” VaryByCustom=”browser” Shared=”true %﹥

    最后,该示例将ASP.NET缓存用户控件 60 秒,并且将针对每个浏览器名称和主要版本创建一个缓存条目。然后,每个浏览器的缓存条目将由引用此用户控件的所有页面共享(只要所有页面都用相同的 ID 引用该控件即可)。 页面级和用户控件级输出缓存的确是一种可以迅速而简便地提高站点性能的方法,但是ASP.NET缓存的真正灵活性和强大功能是通过Cache 对象提供的。使用 Cache 对象,您可以存储任何可序列化的数据对象,基于一个或多个依赖项的组合来控制缓存条目到期的方式。这些依赖项可以包括自从项被缓存后经过的时间、自从项上次被访问后经过的时间、对文件和/或文件夹的更改以及对其他缓存项的更改,在略作处理后还可以包括对数据库中特定表的更改。

    //**************************

    ASP.NET 的输出缓存
    衡量高性能、可缩放的 web 应用程序最重要的一个指标就是缓存了。 ASP.NET 提供了高性能的 web 应用程序的缓存功能 ,ASP.NET 有三种可由 Web 应用程序使用的缓存:
    ·  输出缓存 ,它缓存请求所生成的动态响应。
    ·  片断缓存 ,它缓存请求所生成的响应的各部分。
    ·  数据缓存 ,它以编程方式缓存任意对象。为支持这种缓存, ASP.NET 提供了全功能的缓存引擎,使程序员能够轻松地在请求间保留数据。
    页的输出缓存是非常有用的。在海量的访问站点中,有些页面的访问频率占了非常大的比重,即使对这些页使用输出缓存很少的时间,也会减轻系统不少的负担,因为后面对这些页面的请求将不在执行创建该页的代码。
    但是,这样显得不够灵活,页的请求可能的确是很多,然而在页面上我们缓存了所有的东西,无论是构造成本高还是构造成本低的部分。能否有一种可以缓存页的部分的数据呢?幸运的是 ASP.NET 提供了针对每个请求来创建或自定义该页的各部分。比如说我们可以对页面上构造成本很高的用户控件做片断缓存。
    ASP.NET 缓存支持文件和缓存键依赖项,使开发人员可以使缓存项依赖于外部文件或其他缓存项。此项技术可用于在项的基础数据源发生更改时使该项无效。 ASP.NET 可以将这些项存储在 Web 服务器上或请求流中的其他软件上,例如代理服务器或浏览器。这可以使您避免重新创建满足先前请求的信息,特别是当在服务器上创建时要求大量处理器时间或其他资源的信息。
    Petshop 的页缓存设置
    我们可以可通过使用低级别的 OutputCache API 或高级别的 @ OutputCache 指令来实现页的输出缓存。 启用输出缓存后,当发出对页的第一个 GET 请求时创建一个输出缓存项。随后的 GET 或 HEAD 请求由该输出缓存项服务,直到该缓存请求过期。 输出缓存还支持缓存的 GET 或 POST 名称 / 值对的变体。
    输出缓存遵循页的过期和有效性策略。如果某页位于输出缓存中,并且有一个过期策略标记指示该页自缓存起 60 分钟后过期,则在 60 分钟后将该页从输出缓存中移除。如果此后接收到另一个请求,则执行页代码,并且可以再次缓存该页。
    下面的指令在响应时激活输出缓存:
    <%@ OutputCache Duration="60" VaryByParam="none"%>
    Duration 和 VaryByParam 是必选参数,前者标识过期时间,后者表示 GET 或 POST 名称 / 值对的字符串。如果不使用该属性,可是设置为 none 。在这里我们还要说明一个参数 VaryByCustom ,使用这个参数,我们可以自定义输出缓存要求的任意文本。除了在 OutputCache 指令里面申明该属性之外,我们还得在应用程序的 global.asax 文件的代码声明块中,重写 GetVaryByCustomString 方法来为自定义字符串指定输出缓存的行为。
    举一列来说:
    <%@ OutputCache VaryByParam="none" VaryByCustom="CategoryPageKey" Location="server" Duration="43200" %>
    这里的 VaryByCustom 定义的为 CategoryPageKey ,那么在 global.asax 里面我们必须定义 CategoryPageKey 这个字符创输出缓存的行为,见下面代码。
    public override string GetVaryByCustomString(HttpContext context, String arg) {
                  string cacheKey = "";
                  switch (arg) {
                       case "CategoryPageKey":
                           if (Request.IsAuthenticated == true ) {
                                cacheKey = "QQQ" + context.Request.QueryString["category_id"] + context.Request.QueryString["requestedPage"];
                           }
                           else {
                                cacheKey = "AAA" + context.Request.QueryString["category_id"] + context.Request.QueryString["requestedPage"];
                           }
                           break ;
                       case "SearchPageKey" :
                           if (Request.IsAuthenticated == true ) {
                                cacheKey = "QQQ" + context.Request.QueryString["search_text"] + context.Request.QueryString["requestedPage"];
                           }
                           else {
                                cacheKey = "AAA" + context.Request.QueryString["search_text"] + context.Request.QueryString["requestedPage"];
                           }
                           break ;
                       case "ProductPageKey" :
                           if (Request.IsAuthenticated == true ) {
                                cacheKey = "QQQ" + context.Request.QueryString["name"] + context.Request.QueryString["product_id"] + context.Request.QueryString["requestedPage"];
                           }
                           else {
                                     cacheKey = "AAA" + context.Request.QueryString["name"] + context.Request.QueryString["product_id"] + context.Request.QueryString["requestedPage"];
                           }
                           break ;
                       case "ProductDetailsPageKey" :
                           if (Request.IsAuthenticated == true ) {
                                cacheKey = "QQQ" + context.Request.QueryString["item_id"] + context.Request.QueryString["requestedPage"];
                           }
                           else {
                                cacheKey = "AAA" + context.Request.QueryString["item_id"] + context.Request.QueryString["requestedPage"];
                           }
                           break ;
                       case "UserID" :
                           if (Request.IsAuthenticated == true ) {
                                cacheKey = "UserID_In";
                           }
                           else {
                                cacheKey = "UserID_Out";
                           }
                           break ;
                  }
                  return cacheKey;
             }
    从上面对 CategoryPageKey 字符创所作的行为来看,当我们的请求页面中含有对特定的 category_id的某一分页显示的数据页的请求时,将调用缓存(自然是已经缓存了该页)。
    下表列出了petshop的web应用程序的输出缓存设置。
    ASP.NET WebForms  Cache setting  Duration 
    ControlHeader  <%@ OutputCache
             Duration="43200"         
             VaryByParam="none"
             VaryByCustom="UserID" %>  12 hours 
    Default  <%@ OutputCache
             Duration="43200"
             VaryByParam="none"
             VaryByCustom="UserID" %>  12 hours 
    Help  <%@ OutputCache
             Duration="43200" 
             VaryByParam="none"
             VaryByCustom="UserID" %>  12 hours 
    Category  <%@ OutputCache
             Duration="43200" 
             VaryByParam="none"
             VaryByCustom="CategoryPageKey " %>  12 hours 
    Product  <%@ OutputCache
             Duration="43200" 
             VaryByParam="none"
             VaryByCustom="ProductPageKey " %>  12 hours 
    ProductDetails  <%@ OutputCache
             Duration="43200" 
             VaryByParam="none"
             VaryByCustom="ProductDetailsPageKey " %>  12 hours 
    Search  <%@ OutputCache
             Duration="43200" 
             VaryByParam="none"
             VaryByCustom="SearchPageKey " %>  12 hours 

    显然 petshop 的 web 页面上部的 ControlHeader 是随着用户登陆的状态有关的,故其设置了 VaryByCustom 属性以来标识用户不同登陆状态的缓存版本。而 Category 页面由于可能被大量的访问,并且数据量很大,是十分有必要缓存的,但是由于数据的随机性很大,存在不同的版本,比如说是不同类别的 Category ,甚至不同的分页显示的数据页,在这里采用了 VaryByCustom 属性以缓存不同版本的页。
    Petshop 片断缓存
    在前面我们提到 ASP.NET 可以提供页的局部数据的缓存,通常是一些构造代价较大的部分,诸如用户控件。在 petshop 里面,大量使用了用户控件(尤其是 .NET 示例程序 Duwamish7.0 使用了更多的用户控件,那些页面简直就是控件的拼装),用户控件的缓存设置方法和 aspx 页的缓存设置方法基本相同,在这里我们不再列出。只有 ControlHeader 控件使用了缓存设置。

     

  • 相关阅读:
    整数幂的求解
    非递归实现不重复序列的全排列(二)
    完整的将日期时间转换为汉字的代码
    如何得到某集合的所有子集合?
    再谈八皇后问题
    大数阶乘的计算(六)
    非递归实现不重复序列的全排列(一)
    非递归实现不重复序列的全排列(三)
    大数阶乘的计算(五)
    关于走楼梯的递归算法
  • 原文地址:https://www.cnblogs.com/Fooo/p/1831092.html
Copyright © 2020-2023  润新知