2009-05-21 49 views
5

对于方法,其中...哪些语言支持没有样板代码的返回值缓存?

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

...需要缓存结果值。

在我的代码下面的结果值缓存模式被重复了很多(在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; 
} 

重复这一结构中的所有时间明显违反干的原则。

理想情况下,我想上面的代码将减少到以下几点:

@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?

+0

(注意,所示代码泄漏,而不是线程安全的) – 2009-05-21 11:14:00

+0

这是运行Web上下文,你每次都必须从数据库中获得Foo的价值? – 2009-05-21 11:22:11

+0

@克里斯:不,问题是上下文无关的。 – knorv 2009-05-21 11:27:51

回答

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'); 
+0

谢谢!这完全匹配,实际上它是一个核心的Perl模块! – knorv 2009-05-21 12:29:39

1

Python有许多装饰者的食谱,例如, decorator module,为此工作(如果的参数都是不可变的),它在JVM和.NET上都有实现。

-1

不是直接回答你的问题,但如果你是维护多个高速缓存,它可能值得使用OSCache(Java)来管理这些缓存。驱逐陈旧的物体等,成为一个你不必担心的问题。

虽然您仍然需要使用“check cache”,“return cached”或“create and add to cache”的基本模式。

+0

感谢您的回答。我知道OSCache,它比HashMap有好处,但我提供的代码只是伪代码来显示机制。我不认为OSCache提供任何“memoize”功能。 – knorv 2009-05-21 11:23:59

-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解决方案所能做到的一件事,而不得不处理一些魔法。

+0

正如你指出的那样仍然非常冗长。我正在寻找一些更精益的方法来在Perl或Python中“记忆”。 – knorv 2009-05-21 11:31:34

0

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

-1

This question/answer解决了C#中的记忆问题。它不会缓存结果,但可以轻松更改以使地图静态使用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; 
    }; 
} 
0

微软T-SQL可以从一个PR一个CLR函数缓存的返回值。查询基础...

(除了在CLR书写时它的方法正确的属性没有样板。)

1

春天的孵化区,springmodules正好有这个功能对Java。

Springmodules cache仍处于0.8版本的水平,但它通常做得很不错,当我尝试过去年。有一些选项可以在弹簧配置文件以及注释中配置缓存 - 这看起来与您的示例非常相似。从他们的文档:

public class TigerCacheableService implements CacheableService { 

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

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