Memoizzazione prematura su casi ovvi

3

Nel codice seguente ci saranno diverse istanze di MainClass .

class MainClass(object):

    def f(self, x):
        # expensive operations.
        # ...
        return 'something'

Ogni istanza chiama f(x) diverse volte e x ha un valore specifico che non cambia durante tali chiamate.

Poiché f() è alquanto costoso, posso utilizzare il decoratore @functools.lru_cache() per memoizzare il chiamate.

Tuttavia, sono preoccupato che si tratti di ottimizzazione prematura.

Domande:

  • Sarebbe pericoloso usare lru_cache() da adesso?
  • Non dovrei preoccuparmi di quali parti del mio codice possono essere ottimizzato (anche se sono ovvi da individuare e facile da ottimizzare)?
  • Devo ignorare completamente la memoizzazione su casi ovvi, o forse prenderne nota (ad esempio #TODO comments ) in modo che sia più semplice quando arriva il momento dell'ottimizzazione?

(Nota: il mio codice attuale è + 10k LOC e sono l'unico dev che ci lavora.)

    
posta Fermi paradox 18.09.2015 - 13:00
fonte

3 risposte

2

Normalmente utilizzi la memoizzazione in cui hai stabilito che il problema che la tua funzione sta tentando di risolvere ha una sottostruttura ottimale. Ciò significa che il problema più grande può essere risolto correttamente in una serie di sottoproblemi di piccole dimensioni. Sembra che tu abbia avuto successo nel realizzarlo e che lo hai risolto in modo ricorsivo, che è anche un modo per suddividere un grosso problema in sottoproblemi.

Se si dispone di codice funzionante e soddisfa tutti i requisiti, compresi i requisiti non funzionali su prestazioni e scalabilità, non è necessario necessariamente migliorare le prestazioni del codice utilizzando la memoizzazione. Ritardare il rilascio di software funzionante per ottimizzare è in genere lo spirito di "Evitare l'ottimizzazione prematura" a mio modesto parere.

Would it be dangerous to use lru_cache() from now?

Dipende da come definisci il pericolo. Se si dispone di una soluzione ricorsiva funzionante senza memoization, l'unico vero pericolo qui è forse l'aggiunta di una maggiore complessità che aumenta il rischio di introdurre un bug nella logica. L'altro rischio è che si potrebbe ritardare il rilascio del software per lavorare su un'ottimizzazione che non è necessaria sulla base di requisiti non funzionali chiaramente definiti.

Potrei anche obiettare che se hai una funzione ricorsiva a lungo termine allora potrebbe esserci un pericolo nel NON usare la memoizzazione!

Ciò che intendo è che per un set di dati sufficientemente grande si corre il rischio di far saltare la pila o di esaurire la memoria. Dovresti fare un test di stress adeguato per assicurarti che la tua soluzione ricorsiva sia a posto.

Should I not care at all about which pieces of my code can be optimized (even if they are obvious to spot, and easy to optimize)?

Se si tratta di una facile ottimizzazione, allora con tutti i mezzi per farlo. L'evasione anticipata dell'ottimizzazione non è tanto una regola dura e veloce, quanto una guida per la vita di uno sviluppatore. È ispirato da alcune altre linee guida soggettive come YAGNI e KISS.

Should I ignore memoization on obvious cases completely, or perhaps note it (e.g. #TODO comments) so that it's easier later on when time for optimization comes?

Assolutamente. Penso che i TODO siano un ottimo modo per lasciare poco spazio a te stesso e agli altri sviluppatori su dove qualcosa potrebbe essere migliorato o fatto meglio. Anche questa è una questione di preferenza personale. Gli sviluppatori di Pro-TODO e Anti-TODO hanno però opinioni molto forti su entrambi i lati e sono entrambi positivi.

    
risposta data 18.09.2015 - 14:30
fonte
1

Non vedo come sarebbe "pericoloso" (l'ulteriore carico di manutenzione che si assume è molto modesto, dopotutto.) ma dovresti fare un benchmark per assicurarti che effettivamente migliori qualcosa.

Se a questo punto il benchmark sembra essere troppo difficile, allora è una ottimizzazione prematura e per ora dovresti semplicemente dimenticarti di questo. Verifica il tuo codice in un secondo momento quando riscontri la necessità di ottimizzare e verifica se questo è un punto in cui i tuoi sforzi di ottimizzazione saranno ben spesi.

    
risposta data 18.09.2015 - 14:29
fonte
1

Se le operazioni costose hanno effetti collaterali, dovrebbero essere preservate. In altre parole, questa funzione non sarà candidata alla memoizzazione.

Se non lo fanno e l'output è costante come nel tuo esempio, allora perché c'è un'operazione costosa lì in primo luogo?

Se la memoizzazione effettivamente aiuta dipende da come viene utilizzata. Il risultato è comunque memorizzato nella cache, quindi non farà alcuna differenza (sarà effettivamente peggio a causa della logica di memorizzazione nella cache).

    
risposta data 18.09.2015 - 14:31
fonte

Leggi altre domande sui tag