Utilizzare le eccezioni per il flusso di controllo al fine di aumentare le prestazioni?

3

Aggiungo molti elementi a un elenco di elenchi. Se l'elenco di elenchi in cui il mio elemento deve essere salvato, non esiste ancora, lo gestisco rilevando un'eccezione e aggiungendo un nuovo elenco al mio elenco di elenchi.

La ragione per cui faccio questo invece di controllare ogni volta, se la lista specificata esiste già, è che aggiungo migliaia di elementi, a pochi elenchi. Quindi il caso, che la lista non è stata ancora creata, si verifica solo poche volte. Quindi penso che sia più veloce sollevare un'eccezione e gestirla, invece di controllare le lunghezze delle liste migliaia di volte.

Ecco un esempio di cosa intendo:

try:
    self.layers[pos].extend(node)
except IndexError:
    self.layers.append([])
    self.layers[pos].extend(nodes)

(So che l'indice pos non può essere più alto della lunghezza dei livelli, quindi aggiungerne uno se si verifica un errore è sempre sufficiente)

Quindi tornando alla mia domanda, è quella cattiva pratica di codifica, o è giusto farlo in questo modo per prestazioni?

Ho trovato questa discussione a riguardo, ma le prestazioni non erano un argomento lì.

    
posta Jonas 14.05.2016 - 23:11
fonte

5 risposte

-1

Sì, questa è una cattiva pratica di codifica, poiché offusca ciò che sta accadendo.

Peggio ancora, dal momento che lanciare un'eccezione è un'operazione così costosa in quasi tutte le lingue, questo non ti darà nemmeno nulla sul rendimento! (Anche se misurerei per essere sicuro)

    
risposta data 14.05.2016 - 23:19
fonte
4

L'uso di eccezioni per il controllo del flusso è molto disapprovato nella maggior parte delle lingue, ma non in Python. L'uso di eccezioni per il controllo del flusso in Python è "pythonic". Le eccezioni sono al centro del funzionamento di python for loop, che interrompono l'iterazione alla ricezione di un'eccezione StopIteration . Python ha un termine un po 'spregiativo per le lingue come C ++, Java e C #, dove i programmatori sono caldamente consigliati di * mai * usare le eccezioni per il controllo del flusso. Queste sono le lingue "Guarda prima di saltare" (LBYL).

Python d'altra parte è un linguaggio EAFP: è più facile chiedere perdono che il permesso. L'utilizzo di eccezioni per il controllo del flusso è il cuore della lingua. Il tuo codice è piacevolmente pitonico.

Detto questo, se ti ritrovi a ripetere te stesso in più punti, potresti voler seguire il principio DRY (non ripeterti te stesso) e creare un elenco di elenchi ( LoL ) (o forse una classe defaultlist e quindi evito il mio senso dell'umorismo secco) che estende la classe list incorporata. Dovrai sovrascrivere il metodo __setitem__ (e possibilmente il metodo __getitem__ ) in modo che gli elementi mancanti siano compilati con una lista vuota. Quindi puoi aggiungere a piacere e non dovrai nemmeno utilizzare un blocco try / except . Ora il tuo codice seguirà il principio "Nike": fallo e basta.

    
risposta data 15.05.2016 - 02:51
fonte
2

Python ha un metodo incorporato setdefault che fa esattamente ciò di cui hai bisogno:

self.layers.setdefault("pos", []).extend(node)
    
risposta data 14.05.2016 - 23:46
fonte
0

Ho sentito molto male questa idea sbagliata: "le eccezioni sono situazioni nel tuo codice che non dovresti mai raggiungere. Con il loro nome suggeriscono situazioni eccezionali, inaspettate e incontrollabili. Lanciare un'eccezione dovrebbe interrompere l'esecuzione del codice tutti insieme. "

Ciò è errato perché, supponiamo di voler accedere a un file, e non è possibile accedere al file perché è bloccato, quindi viene generata un'eccezione "File bloccato"; che cosa hai intenzione di fare? Fermare il programma? Se si sta scrivendo un'applicazione GUI, l'unica cosa ragionevole da fare è visualizzare una finestra di dialogo "riprova, annulla", ovvero rilevare l'eccezione e intervenire su di essa.

La citazione è effettivamente pericolosa perché potrebbe richiedere al programmatore inesperto di fare qualcosa come if (not resource_is_locked) access_resource che, ovviamente, apparirà per funzionare, ma fallirà in circostanze apparentemente casuali in condizioni di competizione.

L'unica parte della citazione sopra che è vera è che le eccezioni suggeriscono situazioni eccezionali . Dal momento in cui si cattura l'eccezione diventa una situazione prevista, e dal momento in cui si inserisce qualsiasi codice nel blocco catch è una situazione controllata.

Quindi, è perfettamente corretto definire una situazione come "eccezionale" e gestirla con un'eccezione. Non lo chiamerei controllo del flusso . Lo chiamerei semplicemente gestione delle eccezioni .

Assicurati di a) prima esaurisci tutte le altre possibilità di farlo elegantemente senza eccezioni eb) se devi farlo usando le eccezioni, quindi documenta chiaramente cosa sta succedendo.

Tieni presente che in Windows con Dotnet, lanciare un'eccezione è terribilmente costosa a causa del modo in cui microsoft ha implementato le cose. In Java, in Windows o in Linux, lanciare e catturare un'eccezione non è molto costoso. (Anche se è ancora più costoso di quanto dovrebbe essere, secondo me.)

    
risposta data 14.05.2016 - 23:19
fonte
0

Prima di tutto, se non sai che il pezzo di codice in questione è in realtà un collo di bottiglia per le prestazioni, non preoccuparti di ottimizzarlo e di scriverlo nel modo più chiaro e diretto che puoi immaginare.

Se l'eccezione è più veloce del controllo esplicito dipende interamente dalla lingua / dal compilatore. Per essere più precisi, ci sono due punti in gioco:

  1. Per lanciare l'eccezione, il codice macchina deve codificare un controllo implicito. Se codifichi tu stesso un controllo esplicito, questo duplica la quantità di controlli che vengono eseguiti. Questo dovrebbe davvero rallentare il tuo codice.

  2. Lanciare un'eccezione è eccezionalmente costoso in molte lingue. Potrebbe richiedere una grande quantità di doppi controlli evitati per compensare una singola eccezione che viene lanciata. Ciò potrebbe facilmente rendere il tuo codice ottimizzato molto più lento.

Dipende interamente dal compilatore se è in grado di ottimizzare il controllo implicito che controlla l'eccezione se si scrive un controllo esplicito per la stessa condizione nel codice. Quindi, se il compilatore è abbastanza intelligente, il controllo esplicito sarà sempre più veloce. Tuttavia, se il compilatore è stupido ma gestisce l'eccezione in modo rapido, il controllo basato sull'eccezione implicita è più veloce.

Come tale, la verità è solo in misura. Implementare entrambe le versioni, eseguirle attraverso un test prestazionale realistico, misurare i tempi di esecuzione e confrontare. Qualsiasi altra cosa è solo congetture.

    
risposta data 14.05.2016 - 23:59
fonte

Leggi altre domande sui tag