2011-09-22 17 views
8

Durante la lettura della documentazione sul modulo Python re ho deciso di dare un'occhiata al codice sorgente re.py.Cancellazione cache del modulo Python

Quando l'ho aperto, ho trovato questo:

_cache = {} 
_MAXCACHE = 100 

def _compile(*key): 
    cachekey = (type(key[0]),) + key 
    p = _cache.get(cachekey) 
    if p is not None: 
     return p 

    #...Here I skip some part of irrelevant to the question code... 

    if len(_cache) >= _MAXCACHE: 
     _cache.clear() 
    _cache[cachekey] = p 
    return p 

Perché la cache cancellata usando _cache.clear() quando raggiunge _MAXCACHE di voci?

È un approccio comune cancellare completamente la cache e iniziare da zero?

Perché non utilizzato il valore incassato più tempo fa viene cancellato?

+3

Interessante domanda. Suppongo che potrebbe essere stata la pigrizia da parte dello sviluppatore che ha scritto questo codice, o forse il pensiero "Semplice è meglio del complesso". :-) – NPE

+0

Ho pensato che potrebbe esserci qualche ricerca scientifica che giustifica tale approccio di compensazione della cache al raggiungimento di un valore costante in termini di dimensioni. – ovgolovin

+0

Potrebbe essere interessante osservare la sorgente del nuovo modulo regex in fase di sviluppo qui rintracciato: http://bugs.python.org/issue2636. La descrizione include il termine "Smart Caching", quindi potrebbero esserci alcuni miglioramenti apportati in quell'area. –

risposta

3

Se dovessi indovinare, direi che è stato fatto in questo modo per evitare di dover tenere traccia di quando/per quanto tempo i singoli valori sono stati archiviati nella cache, il che creerebbe sia memoria che elaborazione. Poiché l'oggetto di caching in uso è un dizionario, che è intrinsecamente non ordinato, non c'è un buon modo per sapere quali articoli di ordine sono stati aggiunti ad esso senza alcun altro oggetto di memorizzazione nella cache. Questo potrebbe essere risolto usando OrderedDict al posto di un dizionario standard, supponendo che tu stia lavorando con Python> = 2.7, ma in caso contrario, avresti bisogno di ridisegnare in modo significativo il modo in cui è stato implementato il caching per eliminare la necessità di un clear().

+0

È difficile implementare 'cache' usando' OrderedDict'? A mio avviso, l'uso degli elementi consente di disporli in ordine di ultimo utilizzo. E il riutilizzo di un oggetto compilato richiederebbe semplicemente di spostare il valore memorizzato nella cache all'inizio di "OrderedDict" inserendolo e reinserendolo nel dizionario. – ovgolovin

+0

@ovgolovin - È possibile inserire/aggiungere nuovamente il valore per spostarlo nuovamente in fondo all'elenco, è possibile. Non lo considererei difficile, no. –

+0

Ho pensato che potrebbe esserci qualche ricerca scientifica che giustifica tale approccio di compensazione della cache al raggiungimento di un valore costante in termini di dimensioni. – ovgolovin

1

Il punto di memorizzazione nella cache consente di ridurre il tempo di chiamata medio della funzione. Il sovraccarico associato alla conservazione di maggiori informazioni in _cache e alla sua eliminazione invece di azzerarlo aumenterebbe il tempo medio di chiamata. La chiamata _cache.clear() verrà completata rapidamente e, anche se si perde la cache, è preferibile mantenere uno stato della cache e avere il sovraccarico di rimuovere singoli elementi dalla cache quando viene raggiunto il limite.

ci sono un paio di cose a cui pensare quando si calcola l'efficienza della cache:

  1. Tempo medio di chiamata su riscontri nella cache (molto breve)
  2. Tempo medio chiamata cache miss (più lungo)
  3. di frequenza di colpi di cache (abbastanza raro)
  4. chiamata momento in cui la cache viene cancellata o potata (piuttosto raro)

La domanda è che l'aumento # 3 ha senso se significa aumentare anche il numero 2 e il numero 4. La mia ipotesi è che non è così, o la differenza è abbastanza trascurabile che è preferibile mantenere il codice semplice.

+0

Ma l'overhead associato a mantenere più informazioni in '_cache' sarà prevedibile. Ma cancellare '_cache' in momenti sporadici renderà la valutazione dell'efficienza della cache molto fastidiosa, poiché sarà molto affidabile nei momenti in cui' cache' viene cancellato. – ovgolovin

5

Ecco una citazione da uno degli sviluppatori di un nuovo modulo regex prevista per 3.3 per quanto riguarda la memorizzazione nella cache, questo fa parte di un elenco di caratteristiche che separa il nuovo modulo dal modulo corrente re.

7) Modificare la cache di espressioni ricompilate per gestire meglio la condizione di thrash . Attualmente, quando vengono compilate le espressioni regolari, il risultato viene memorizzato nella cache in modo che se la stessa espressione viene compilata di nuovo, viene recuperata dalla cache e non è necessario eseguire ulteriori operazioni. Questa cache supporta fino a 100 voci. Una volta raggiunta la 100a voce, la cache viene cancellata e deve essere eseguita una nuova compilazione.Il pericolo, che si tratti di raro, è che si può compilare la 100esima espressione solo per scoprire che uno ricompila e deve fare lo stesso lavoro tutto da capo quando potrebbe essere stato fatto 3 espressioni fa. Modificando leggermente questa logica, è possibile stabilire un contatore arbitrario che fornisce un timestamp a ogni voce compilata e invece di svuotare l'intera cache quando raggiunge la capacità , eliminare solo la metà più vecchia della cache, mantenendo la metà è più recente. Ciò dovrebbe limitare la possibilità che si blocchi nei casi in cui un numero molto elevato di espressioni regolari è continuamente ricompilato. Oltre a ciò, aggiornerò il limite alle voci 256, il che significa che le 128 più recenti sono conservate.

http://bugs.python.org/issue2636

Questo sembra indicare che è più probabile la pigrizia dello sviluppatore o "l'accento sulla leggibilità" che spiega il comportamento della cache corrente.

+0

Ho aperto il codice sorgente di 'regex' del modulo (lo uso da circa due settimane). Il blocco di codice responsabile della cancellazione della cache è il seguente 'if len (_cache)> = _MAXCACHE: shrink_cache (_cache, _named_args, _MAXCACHE)'. Ma non ho trovato alcuna funzione 'shrink_cache' sul modulo. Non esiste tale funzione. – ovgolovin

+0

Tuttavia, l'autore continua ad eliminare grandi blocchi di cache, non singoli elementi quando è necessario. Il nuovo approccio elimina la meno recente metà della cache. – ovgolovin

Problemi correlati