Utilizzando "intercettare le eccezioni" per migliorare la leggibilità, buona o cattiva?


9

Nella sezione Quando usare l'eccezione in The Pragmatic Programmer , il libro scrive che invece di:

retcode = OK;
     if (socket.read(name) != OK) {
      retcode = BAD_READ;
    }
     else {
      processName(name);
       if (socket.read(address) != OK) {
        retcode = BAD_READ;
      }
       else {
        processAddress(address);
         if (socket.read(telNo) != OK) {
          retcode = BAD_READ;
        }
         else {
          //  etc, etc...
        }
      }
    }
     return retcode;

, preferiscono:

 retcode = OK;
     try {
      socket.read(name);
      process(name);
      socket.read(address);
      processAddress(address);
      socket.read(telNo);
      //  etc, etc...
    }
     catch (IOException e) {
      retcode = BAD_READ;
      Logger.log( "Error reading individual: " + e.getMessage());
    }
     return retcode;

semplicemente perché sembra più ordinato. Sono tutto per il codice più ordinato, tuttavia non è inutile catturare le eccezioni un collo di bottiglia delle prestazioni?

Posso capire che dovremmo rinunciare all'ottimizzazione minuscola per il codice più ordinato (almeno il 99% delle volte), tuttavia da quello che so, la cattura delle eccezioni appartiene alla classe di codice che ha un notevole ritardo nel runtime. Quindi mi chiedevo qual è la giustificazione che il secondo pezzo di codice è preferito rispetto al primo codice?

O meglio, quale codice preferiresti?


migrato da Code Review perché è una domanda di best practice non una domanda di revisione del codice
Winston Ewert

1
IMO, se ti aspetti di essere in grado di leggere quei valori validi dal socket, allora un IOEx è eccezionale.
Steven Evers,


Hai misurato?

@ ThorbjørnRavnAndersen ovviamente stavo leggendo il libro e non ho un vero "test case" per misurare .. ma se lo misuriamo in un codice forzato, allora ovviamente c'è una penalità prestazionale allora
Pacerier

Risposte:


18

Le eccezioni sono in genere più lente solo se effettivamente lanciate. Di solito, le eccezioni in situazioni come questa sono rare, quindi non è qualcosa di cui dovresti preoccuparti. Dovresti davvero preoccuparti dell'esecuzione delle eccezioni se si verificano continuamente e quindi sono un fattore significativo.

Il secondo codice è migliore perché è molto più facile seguire la logica. La gestione degli errori è ben localizzata. L'unica obiezione è che se si utilizzano le eccezioni, utilizzare le eccezioni. Non catturare le eccezioni e quindi restituire un codice di errore.


4
D'accordo, odio vedere i codici di errore in una lingua che ha delle eccezioni. La maggior parte delle volte dovresti catturare, accedere, ricominciare senza rompere lo stack di chiamate. E il più delle volte, non importa se un caso di "eccezione" è più lento. L'app ha un problema, prenditi il ​​tempo necessario per gestirla correttamente. Fintanto che l'eccezione è eccezionale e non fa parte del normale funzionamento o del percorso felice dell'applicazione, di solito non è un odore di codice.
CaffGeek,

Tra l'altro mi chiedevo come possiamo giustificare l'EOFException che DataStreams utilizza per rilevare un fine linea (fine linea non è eccezionale) come dimostrato in docs.oracle.com/javase/tutorial/essential/io/datastreams.html ?
Pacerier,

@Pacerier, potrebbe essere eccezionale. A corto di input nella riga potrebbe indicare dati errati o qualcosa che va terribilmente storto. Sospetto che l'uso previsto sia quello di analizzare diversi campi da una riga.
Winston Ewert,

@Downvoter, se hai un problema con la risposta, ti preghiamo di spiegare!
Winston Ewert,

5

Bene, come si suol dire, le eccezioni dovrebbero gestire casi eccezionali , e dato che si tratta di un caso eccezionale (vale a dire qualcosa che accade poco e molto in mezzo) direi che questo vale anche qui.

Inoltre, vorrei consigliare contro cose micro-ottimizzazione, come questo. Concentrati maggiormente sulla leggibilità del codice , poiché passerai molto più tempo a leggere il codice che a scrivere un nuovo codice.

Per assicurarti davvero che si tratti di un collo di bottiglia nelle prestazioni, fai un po 'di profilazione e analizza e focalizza le attività più critiche sulla base di tale analisi.


5

Posso capire che dovremmo rinunciare all'ottimizzazione minuscola per il codice più ordinato (almeno il 99% delle volte), tuttavia da quello che so, la cattura delle eccezioni appartiene alla classe di codice che ha un notevole ritardo nel runtime.

Da dove lo sai? Come si definisce "notevole ritardo"?

Questo è esattamente il tipo di mito prestazionale vago (e completamente sbagliato) che porta a inutili ottimizzazioni premature.

Generare e catturare un'eccezione può essere lento rispetto all'aggiunta di due numeri, ma è completamente insignificante rispetto alla lettura dei dati da un socket. Probabilmente potresti lanciare e catturare mille eccezioni nello stesso tempo in cui hai letto un singolo pacchetto di rete. E non stiamo parlando di migliaia di eccezioni qui, solo una singola.


Vengo da .NET, quindi scusate la mia conoscenza di Java, ma ho sperimentato personalmente delle eccezioni di cattura in .NET che causavano ritardi folli (magnitudo di secondi) che sono stati risolti rimuovendo il "codice di cattura delle eccezioni".
Pacerier,

@Pacerier, sul serio? magnitudo di secondi? Immagino che forse stessero prendendo molte eccezioni? Allora ho potuto vederlo.
Winston Ewert,

3
@Pacerier: se le eccezioni stanno causando ritardi folli, chiaramente ciò che le sta causando non è eccezionale, e quindi dovrebbe essere gestito in altri modi. Nessun sistema dovrebbe impiegare pochi secondi per elaborare un'eccezione e penso che Microsoft sia sufficientemente competente per evitarlo.
David Thornley,

5

Sono d'accordo con le risposte che hai già ottenuto dicendo che questo è un caso eccezionale, quindi è ragionevole usare la gestione delle eccezioni.

Affrontando le tue prestazioni in modo più diretto, penso che tu debba mantenere un senso di scala sulle cose. Lanciare / catturare un'eccezione in queste circostanze è probabile che prenda uno dell'ordine di un microsecondo. Come va il controllo del flusso, è lento - molte volte più lento delle normali ifaffermazioni, nessuna domanda al riguardo.

Allo stesso tempo, tieni presente che quello che stai facendo qui è leggere i dati da una rete. A 10 megabit al secondo (lento per una rete locale, ma abbastanza veloce come vanno le connessioni Internet), è nello stesso ordine del tempo di lettura di un byte di informazioni.

Ovviamente, quel sovraccarico si verifica solo quando si lancia effettivamente anche l'eccezione - quando non viene generato, di solito c'è poco o nessun sovraccarico (almeno da quello che ho visto, il sovraccarico più significativo non proviene dal gestione delle eccezioni stessa, come dall'aggiunta di più potenziali flussi di controllo, rendendo il codice più difficile da ottimizzare anche per il compilatore).

In questo caso, quando viene generata un'eccezione, i dati di scrittura nel registro. Data la natura della registrazione, è molto probabile che svuoti quell'output non appena lo scrivi (per assicurarti che non vada perso). Scrivere su disco è (di nuovo) un'operazione piuttosto lenta - è necessario un SSD di classe enterprise abbastanza veloce per arrivare anche nell'intervallo di decine di migliaia di IOP / secondo. Un disco utilizzato per la registrazione potrebbe essere facilmente limitato a qualcosa come centinaia di IOP / secondo.

In conclusione: ci sono casi in cui l'overhead di gestione delle eccezioni può essere significativo, ma quasi sicuramente non è uno di questi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.