哪种语言支持没有样板代码的返回值缓存?

时间:2009-05-21 11:02:40

标签: c# java performance language-agnostic caching

对于......

的方法
  • 输入和输出之间存在静态一对一映射,
  • 创建输出对象的成本相对较高,
  • 使用相同的输入重复调用该方法

...需要缓存结果值。

在我的代码中,以下结果值缓存模式重复了很多(Java中的伪代码,但问题与语言无关):

private static Map<Input, Output> fooResultMap = new HashMap<Input, Output>();
public getFoo(Input input) {
  if (fooResultMap.get(input) != null) {
    return fooResultMap.get(input);
  }
  Output output = null;
  // Some code to obtain the object since we don't have it in the cache.
  fooResultMap.put(input, output);
  return output;
}

一直重复这种结构明显违反DRY原则。

理想情况下,我希望将上面的代码简化为以下内容:

@CacheResult
public getFoo(Input input) {
  Output output = null;
  // Some code to obtain the object since we don't have it in the cache.
  return output;
}

理论上的CacheResult注释会处理我目前正在手工完成的缓存。

此类缓存的一般术语是“memoization”。

我正在寻找的确切功能的一个很好的例子是Perl core module "Memoize"

在哪种语言中存在类似Memoize的缓存解决方案(在语言级别或库级别)?特别是 - 对于任何主要平台,例如Java或.NET,是否存在这样的解决方案?

9 个答案:

答案 0 :(得分:4)

不是内置的语言,我认为CPAN模块Memoize在Perl土地上相当受欢迎:

   # Compute Fibonacci numbers
    sub fib {
      my $n = shift;
      return $n if $n < 2;
      fib($n-1) + fib($n-2);
    }

    use Memoize;
    memoize('fib');

答案 1 :(得分:2)

缓存处理程序 - 在.Net'企业库'中

http://msdn.microsoft.com/en-us/library/cc511757.aspx

[CachingCallHandler(0, 0, 30)]
public decimal GetSavingsBalance(int accountNumber)
{
  // Code here to extract balance from database.
  return balance;
}

答案 2 :(得分:1)

Python有许多装饰器配方,例如decorator module,适用于此( if 参数都是不可变的),并且它在JVM和.NET上都有实现。

答案 3 :(得分:1)

Spring的孵化区域 springmodules 具有Java的这一功能。

Springmodules cache 仍然处于0.8版本的水平,但是当我去年试用它时,它的效果一般都很好。有一些选项可以在spring配置文件和注释中配置缓存 - 这看起来与您的示例非常相似。来自他们的文档:

public class TigerCacheableService implements CacheableService {

  @Cacheable(modelId = "testCaching")
  public final String getName(int index) {
    // some implementation.
  }
...
}

您可以选择缓存的后端实现。当我尝试它时,我有很好的结果将它连接到ehcache,它也有很好的弹簧集成。您可以声明性地设置ehcache来缓存(内存和/或磁盘)您使用 @Cacheable 注释标记的方法的结果。

答案 4 :(得分:0)

您可以在Java中实现@CacheResult注释,例如使用ASMtransform添加记忆代码的方法。

答案 5 :(得分:0)

Microsoft T-SQL可以缓存来自pr的CLR函数的返回值。查询依据......

(在CLR中写入时,除了方法的正确属性外没有样板。)

答案 6 :(得分:-1)

不是您问题的直接答案,但如果您要维护许多缓存,则使用OSCache(Java)来管理这些缓存可能是值得的。驱逐陈旧物品等,成为您不必担心的问题。

你仍然需要使用“检查缓存”,“返回缓存”或“创建并添加到缓存”的基本模式。

答案 7 :(得分:-1)

虽然Java的语法仍然很详细,但可以将Java中的代码分解出来,

private static final Cache<Input, Output> fooCache = Caches.newInstance(
    new Factory<Input, Output>() { public Output create(Input input) {
        return ... some code ...;
    }}
);
public static Output getFoo(Input input) {
    return fooCache.get(input);
}

通过对匿名内部类的更好的语法支持,可能会变成,例如:

private static final Cache<Input, Output> fooCache =
    (Input input) (... some code ...);
public static Output getFoo(Input input) {
    return fooCache.get(input);
}

这是AOP解决方案可以做的一件事,代价是不得不处理一些魔法。

答案 8 :(得分:-1)

This question/answer解决了C#中的Memoization问题。它不会缓存结果,但可以通过ReaderWriterLock轻松更改以使地图静态。

以下是link given的示例:

public static Func<A, R> Memoize<A, R>(this Func<A, R> f)
{
  var map = new Dictionary<A, R>();
  return a =>
    {
      R value;
      if (map.TryGetValue(a, out value))
        return value;
      value = f(a);
      map.Add(a, value);
      return value;
    };
}