2013-02-10 70 views
0

我正在编写Groovy语言的一些培训材料,并且正在准备一个将解释闭包的示例。 的例子是“昂贵”的方法简单缓存关闭,withCache哪个闭包实现在两个示例之间更快

def expensiveMethod(Long a) { 
    withCache (a) { 
     sleep(rnd()) 
     a*5 
    } 
} 

所以,现在我的问题是:这两个以下实现的将是最快,在Groovy更地道?

def withCache = {key, Closure operation -> 

    if (!cacheMap.containsKey(key)) { 
     cacheMap.put(key, operation()) 
    } 
    cacheMap.get(key) 
} 

def withCache = {key, Closure operation -> 
    def cached = cacheMap.get(key) 
    if (cached) return cached 
    def res = operation() 
    cacheMap.put(key, res) 
    res 
} 

我更喜欢的第一个例子,因为它不使用任何可变的,但我不知道是否访问Mapget方法比返回包含该计算结果的变量慢。

显然答案是“这取决于Map的大小”,但出于好奇,我希望得到社区的意见。

谢谢!

+0

你不能也使用memoize? http://mrhaki.blogspot.co.uk/2011/05/groovy-goodness-cache-closure-results.html – 2013-02-10 22:28:02

+0

是的,但它对于引入闭包有点高级。这个问题实际上是一种个人的好奇心,它也适用于Java。 – 2013-02-10 22:31:49

+0

除非这是每秒钟执行数千次的操作,否则几乎没有办法可以做到这一点。 HashMap * lookup *通常是[O(1)操作](http://en.wikipedia.org/wiki/Big_o_notation#Orders_of_common_functions),这是担心性能优化的最糟糕的地方。 – OverZealous 2013-02-11 04:31:28

回答

1

首先我同意OverZealous,担心两个get操作是一个不成熟的优化。第二个exmaple也不等于第一个。例如,第一个允许null,而第二个则使用if中的Groovy-Truth,这意味着空的evals为false,例如空列表/数组/地图。所以如果你想显示调用Closure,我会选择第一个。如果你想要更多的惯用东西,我会这样做,而不是你的情况:

def expensiveMethod(Long a) { 
    sleep(rnd()) 
    a*5 
} 
def cache = [:].withDefault this.&expensiveMethod 
+0

嗨@blackdrag,我不确定我是否完全掌握了你的例子。 .withDefault方法使用null“.get”操作的默认行为来装饰映射,在这种情况下,该操作将调用“expensiveMethod”。但在我的例子中,我想使用“withCache”Closure来按照我喜欢的方法使用缓存。说得通? – 2013-02-11 10:59:02

+0

这是一个让方法进行缓存(你的方式)或提供外部方式的问题。在我的例子中,你当然也可以使用其他闭包和方法。最惯用的方法是恕我直言: 高清expensiveMethod(龙一){ 睡眠(RND()) 一个* 5 } 高清处理=这与expensiveMethod.memoize() 可用,因为Groovy的1.8:HTTP:/ /groovy.codehaus.org/Groovy+1.8+release+notes#Groovy18releasenotes-Closurememoization 这很大程度上取决于你最终想展示什么 – blackdrag 2013-02-13 11:59:26