2009-12-19 26 views
21

Jaki jest najbardziej wydajny sposób budowania pamięci podręcznej z dowolnymi obiektami Ruby jako kluczami, które wygasły w oparciu o ostatnio używany algorytm. Powinien używać zwykłej semantyki ruby ​​(nie równej?)Efektywna pamięć podręczna Ruby LRU

+0

Starasz na minimalnym wykorzystaniu pamięci lub minimalne użycie cpu, jak często usuwacie rzeczy z pamięci podręcznej LRU? Możesz wybrać metodę oczyszczania lub podwójnie połączoną listę ze sparowanym hashiem. –

+0

dla niektórych pomysłów patrz: http://java.sun.com/j2se/1.4.2/docs/api/java/util/LinkedHashMap.html także mongodb ma ograniczoną kolekcję podobnie możesz zrobić to z redis.zakładając, że szukasz wbudowanego rozwiązania typu Ruby, ale –

Odpowiedz

9

To przesuwa granice mojego rozumienia tego, jak Ruby wykorzystuje pamięć, ale podejrzewam, że najbardziej wydajną implementacją byłaby podwójnie związana lista, w której każdy dostęp przesuwa klucz do przodu listy, a każda wstawka upuszcza element, jeśli został osiągnięty maksymalny rozmiar.

Jednak przy założeniu, że klasa Ruby o nazwie Hash jest już bardzo wydajna, założę się, że nieco naiwne rozwiązanie polegające na dodaniu danych o wieku do Hash byłoby całkiem dobre. Oto krótki przykład zabawki, które wykonuje to:

class Cache 
    attr_accessor :max_size 

    def initialize(max_size = 4) 
    @data = {} 
    @max_size = max_size 
    end 

    def store(key, value) 
    @data.store key, [0, value] 
    age_keys 
    prune 
    end 

    def read(key) 
    if value = @data[key] 
     renew(key) 
     age_keys 
    end 
    value 
    end 

    private # ------------------------------- 

    def renew(key) 
    @data[key][0] = 0 
    end 

    def delete_oldest 
    m = @data.values.map{ |v| v[0] }.max 
    @data.reject!{ |k,v| v[0] == m } 
    end 

    def age_keys 
    @data.each{ |k,v| @data[k][0] += 1 } 
    end 

    def prune 
    delete_oldest if @data.size > @max_size 
    end 
end 

Jest prawdopodobnie szybszy sposób na znalezienie najstarszy element, a to nie jest dokładnie testowane, ale byłbym ciekaw, jak ktoś myśli, że to porównać do bardziej wyrafinowany projekt, połączona lista lub w inny sposób.

+0

delete_oldest to O (n), które jest nieefektywne, możesz to zrobić w stałym czasie, jeśli używasz innej implementacji – Noam

1

Blog o Ruby Best Practices ma na ten temat numer post.

2

rufus-LRU gem ma innej opcji.

Zamiast liczyć tylko tam posortowaną tablicę kluczy od najstarszego do najnowszego

2

rzucałem razem nowy klejnot lrucache, które mogą okazać się przydatne. Może być szybszy niż podejście Alexa do kolekcji ze znaczną liczbą elementów.

27

Wiem, że kilka lat spóźnione, ale ja po prostu realizowane w co wierzę jest najszybszym LRU cache tam dla Ruby.

Jest również testowany i opcjonalnie bezpieczny w środowiskach wielowątkowych.

https://github.com/SamSaffron/lru_redux


Uwaga: w Ruby 1.9 Hash jest uporządkowane, dzięki czemu można oszukać i zbudować najszybszą LRU cache w kilku liniach kodu

class LruRedux::Cache19 

    def initialize(max_size) 
    @max_size = max_size 
    @data = {} 
    end 

    def max_size=(size) 
    raise ArgumentError.new(:max_size) if @max_size < 1 
    @max_size = size 
    if @max_size < @data.size 
     @data.keys[[email protected][email protected]].each do |k| 
     @data.delete(k) 
     end 
    end 
    end 

    def [](key) 
    found = true 
    value = @data.delete(key){ found = false } 
    if found 
     @data[key] = value 
    else 
     nil 
    end 
    end 

    def []=(key,val) 
    @data.delete(key) 
    @data[key] = val 
    if @data.length > @max_size 
     @data.delete(@data.first[0]) 
    end 
    val 
    end 

    def each 
    @data.reverse.each do |pair| 
     yield pair 
    end 
    end 

    # used further up the chain, non thread safe each 
    alias_method :each_unsafe, :each 

    def to_a 
    @data.to_a.reverse 
    end 

    def delete(k) 
    @data.delete(k) 
    end 

    def clear 
    @data.clear 
    end 

    def count 
    @data.count 
    end 

    # for cache validation only, ensures all is sound 
    def valid? 
    true 
    end 
end 
Powiązane problemy