【问题标题】:Caching attribute for method?方法的缓存属性?
【发布时间】:2011-07-16 18:36:25
【问题描述】:

也许这是在做梦,但是是否可以创建一个属性来缓存函数的输出(例如,在 HttpRuntime.Cache 中)并从缓存中返回值,而不是在函数的参数时实际执行函数一样吗?

当我说函数时,我指的是任何函数,它是否从数据库中获取数据,是否添加两个整数,或者是否吐出文件的内容。任何功能。

【问题讨论】:

  • 也许你在谈论嘲笑?
  • 我想知道使用dynamic 来实现这有多可行。创建一个接受动态调用的包装器,调用实际对象并将结果缓存起来。
  • @Matt Greer 你不需要动态来实现这样的事情,因为你已经接受放弃使用 AOP 来做这件事。我创建了一个基类Cacheable<T>,你所做的就是从它继承,定义一个缓存区域并给它一个关于如何在缓存未命中时加载缓存的 lambda 语句。
  • @Chris Marisic -- 你介意分享你的Cacheable<T> 课程吗?我想看看。
  • @PostgresQLNewb:我用今天找到的新链接更新了我的旧答案,以防你仍然对这些东西感兴趣

标签: c# .net asp.net caching


【解决方案1】:

您最好的选择是Postsharp。我不知道他们是否有你需要的东西,但这当然值得检查。顺便说一句,如果您找到答案,请务必在此处发布答案。

编辑:此外,谷歌搜索“postsharp 缓存”会提供一些链接,例如:Caching with C#, AOP and PostSharp

更新:我最近偶然发现了这篇文章:Introducing Attribute Based Caching。如果您仍在寻找解决方案,它会在 http://cache.codeplex.com/ 上描述基于 postsharp 的库。

【讨论】:

  • 这段代码很棒,我刚刚下载并用于我的项目。但是我遇到了麻烦,因为我使用的是 64 位电脑,而且我认为演示是针对 x86 的。所以我不得不逐个文件复制代码文件。之后工作正常
【解决方案2】:

您可以使用逗号分隔的字符串将字典添加到您的类中,其中函数名作为键,结果作为值。然后,当您的函数可以检查字典是否存在该值时。将字典保存在缓存中,以供所有用户使用。

【讨论】:

  • 函数名显然不足以作为键,我认为它必须依赖于参数。但我很确定在方法的开头添加普通的缓存/检索代码不是 OP 正在寻找的
【解决方案3】:

AFAIK,坦率地说,没有。

但这将是在框架内实现的一项艰巨任务,以便它在所有情况下都能通用地为每个人工作 - 但是,您可以通过简单地定制一些足以满足需求的东西(其中简单性与需求相关) ,显然)使用抽象、继承和现有的ASP.NET Cache

【讨论】:

    【解决方案4】:

    如果您想创建可以在任何地方使用任何方法的[Cache] 属性(或类似属性),PostSharp 是您的一站式商店。以前当我使用 PostSharp 时,我永远无法超越它让我的构建变得多么缓慢(这是 2007 年的事,所以这可能不再相关了)。

    另一种解决方案是考虑将 Render.Partial 与 ASP.NET MVC 与 OutputCaching 结合使用。这是为小部件/页面区域提供 html 的绝佳解决方案。

    使用 MVC 的另一个解决方案是将您的 [Cache] 属性实现为 ActionFilterAttribute。这将允许您采用控制器方法并将其标记为缓存。它只适用于控制器方法,因为 AOP 魔法只能在 MVC 管道期间与 ActionFilterAttributes 一起发生。

    通过 ActionFilterAttribute 实施 AOP 已发展成为我商店的 goto 解决方案。

    【讨论】:

      【解决方案5】:

      我也遇到了同样的问题 - 我的应用程序中有多种昂贵的方法,我有必要缓存这些结果。前段时间我只是复制粘贴了类似的代码,但后来我决定将这个逻辑排除在我的领域之外。 这是我之前的做法:

          static List<News> _topNews = null;
          static DateTime _topNewsLastUpdateTime = DateTime.MinValue;
          const int CacheTime = 5;  // In minutes
      
          public IList<News> GetTopNews()
          {
              if (_topNewsLastUpdateTime.AddMinutes(CacheTime) < DateTime.Now)
              {
                  _topNews = GetList(TopNewsCount);
              }
      
              return _topNews;
          }
      

      这就是我现在的写法:

          public IList<News> GetTopNews()
          {
              return Cacher.GetFromCache(() => GetList(TopNewsCount));
          }
      

      Cacher - 是一个简单的辅助类,这里是:

      public static class Cacher
      {
          const int CacheTime = 5;  // In minutes
      
          static Dictionary<long, CacheItem> _cachedResults = new Dictionary<long, CacheItem>();
      
          public static T GetFromCache<T>(Func<T> action)
          {
              long code = action.GetHashCode();
      
              if (!_cachedResults.ContainsKey(code))
              {
                  lock (_cachedResults)
                  {
                      if (!_cachedResults.ContainsKey(code))
                      {
                          _cachedResults.Add(code, new CacheItem { LastUpdateTime = DateTime.MinValue });
                      }
                  }
              }
      
              CacheItem item = _cachedResults[code];
              if (item.LastUpdateTime.AddMinutes(CacheTime) >= DateTime.Now)
              {
                  return (T)item.Result;
              }
      
              T result = action();
      
              _cachedResults[code] = new CacheItem
              {
                  LastUpdateTime = DateTime.Now,
                  Result = result
              };
      
              return result;
          }
      }
      
      
      class CacheItem
      {
          public DateTime LastUpdateTime { get; set; }
          public object Result { get; set; }
      }
      

      关于 Cacher 的几句话。您可能会注意到我在计算结果时不使用 Monitor.Enter() ( lock(...) )。这是因为复制 CacheItem 指针(return (T)_cachedResults[code].Result; line)是线程安全的操作——它只需一笔即可执行。如果多个线程同时更改此指针也可以 - 它们都是有效的。

      【讨论】:

      • 但是当另一个线程插入一个值时从字典中读取(TryGetValue)是线程安全的吗?插入会改变字典的内部结构,并且在插入期间从字典中读取可能(我不确定)会导致未定义的行为。
      • 格雷格,我相信是的。 TryGetValue 的内部实现只是在其数组中迭代 if 'for' 循环并搜索适合请求值的哈希键。如果数组发生变化,什么都不会发生
      • GetList(TopNewCount)、GetList(5)和GetList(8)会产生相同的hashcode,导致返回无效结果,因为存储结果时不考虑传入的参数跨度>
      【解决方案6】:

      如果你不需要属性配置但接受代码配置,也许MbCache是你要找的?

      【讨论】:

        猜你喜欢
        • 2011-02-04
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        • 2021-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-09-09
        相关资源
        最近更新 更多