2009-05-21 48 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以緩存(內存和/或磁盤)使用註釋標記的方法的結果。