Quanto sono lente le eccezioni .NET?


143

Non voglio una discussione su quando e non gettare eccezioni. Vorrei risolvere un semplice problema. Il 99% delle volte l'argomentazione per non gettare eccezioni ruota attorno ad esse mentre è lenta mentre l'altra parte afferma (con il test di riferimento) che la velocità non è il problema. Ho letto numerosi blog, articoli e post riguardanti una parte o l'altra. Quindi che cos'è?

Alcuni collegamenti dalle risposte: Skeet , Mariani , Brumme .


13
ci sono bugie, maledette bugie e parametri di riferimento. :)
gbjbaanb,

Sfortunatamente, qui molte risposte non votate hanno mancato che la domanda si ponesse "quanto sono lente le eccezioni?", E in particolare è stato chiesto di evitare l'argomento di quanto spesso usarle. Una semplice risposta alla domanda che, come effettivamente chiesto, è ..... Su Windows CLR, le eccezioni sono 750 volte più lente dei valori restituiti.
David Jeske,

Risposte:


207

Sono dalla parte "non lenta" - o più precisamente "non abbastanza lenta da rendere la pena evitarli nell'uso normale". Ho scritto due brevi articoli su questo. Ci sono critiche all'aspetto del benchmark, che si basano principalmente su "nella vita reale ci sarebbe più stack da attraversare, quindi si soffierebbe la cache ecc." - ma usare i codici di errore per farti strada nello stack sarebbe anche soffiare nella cache, quindi non lo vedo come un argomento particolarmente valido.

Giusto per chiarire: non supporto l'uso di eccezioni in cui non sono logiche. Ad esempio, int.TryParseè del tutto appropriato per convertire i dati da un utente. È appropriato quando si legge un file generato dalla macchina, dove fallimento significa "Il file non è nel formato che dovrebbe essere, non voglio davvero provare a gestirlo perché non so cos'altro potrebbe essere sbagliato. "

Quando ho usato le eccezioni in "solo circostanze ragionevoli" non ho mai visto un'applicazione le cui prestazioni erano significativamente compromesse da eccezioni. Fondamentalmente, le eccezioni non dovrebbero accadere spesso a meno che tu non abbia problemi significativi di correttezza e se hai problemi significativi di correttezza, le prestazioni non sono il problema più grande che devi affrontare.


2
sfortunatamente, alle persone viene detto che le eccezioni sono gratuite, usale per una banale funzionalità 'corretta', dovrebbero essere usate come dici tu, quando le cose sono andate male - in circostanze 'eccezionali'
gbjbaanb

4
Sì, le persone dovrebbero certamente essere consapevoli del fatto che esiste un costo in termini di prestazioni associato all'utilizzo inappropriato delle eccezioni. Penso solo che sia un problema quando vengono utilizzati in modo appropriato :)
Jon Skeet,

7
@PaulLockwood: direi che se hai più di 200 eccezioni al secondo , stai abusando delle eccezioni. Non è chiaramente un evento "eccezionale" se si verifica 200 volte al secondo. Nota l'ultima frase della risposta: "Fondamentalmente, le eccezioni non dovrebbero accadere spesso a meno che tu non abbia problemi significativi di correttezza e se hai problemi significativi di correttezza, le prestazioni non sono il problema più grande che devi affrontare."
Jon Skeet,

4
@PaulLockwood: il mio punto è che se hai più di 200 eccezioni al secondo, questo probabilmente indica già che stai abusando delle eccezioni. Non mi sorprende che ciò avvenga spesso, ma significa che l'aspetto prestazionale non sarebbe la mia prima preoccupazione: l'abuso di eccezioni lo sarebbe. Una volta rimossi tutti gli usi inappropriati delle eccezioni, non mi sarei aspettato che fossero una parte significativa delle prestazioni.
Jon Skeet,

4
@DavidJeske: hai perso il punto della risposta. Ovviamente lanciare un'eccezione è molto più lento che restituire un valore normale. Nessuno lo sostiene. La domanda è se sono troppo lenti. Se ti trovi in ​​una situazione adatta per lanciare un'eccezione e questo sta causando un problema di prestazioni, allora probabilmente hai problemi più grandi, perché suggerisce che c'è un grosso errore nel tuo sistema. Normalmente, il problema è in realtà che si sta utilizzando eccezioni quando sono inadeguato per iniziare.
Jon Skeet,

31

C'è la risposta definitiva a questo da parte del ragazzo che li ha implementati: Chris Brumme. Ha scritto un eccellente articolo di blog sull'argomento (avviso - è molto lungo) (avviso2 - è scritto molto bene, se sei un tecnico lo leggerai fino alla fine e poi dovrai recuperare le ore dopo il lavoro :) )

Il sommario esecutivo: sono lenti. Sono implementati come eccezioni SE32 di Win32, quindi alcuni supereranno addirittura il limite della CPU dell'anello 0! Ovviamente nel mondo reale, farai un sacco di altro lavoro, quindi la strana eccezione non verrà notata affatto, ma se li usi per il flusso del programma aspettati che la tua app venga martellata. Questo è un altro esempio della macchina di marketing MS che ci sta facendo un disservizio. Ricordo una microsofta che ci diceva come si sono verificati assolutamente zero spese generali, che è completa.

Chris dà una citazione pertinente:

In effetti, il CLR utilizza internamente le eccezioni anche nelle parti non gestite del motore. Tuttavia, esiste un grave problema di prestazioni a lungo termine con eccezioni e questo deve essere preso in considerazione nella tua decisione.


Posso menzionarlo nei test del mondo reale, in cui un tipo nullable sta generando un'eccezione molte volte in un "questo è normale flusso di programma", che ha portato a significativi problemi di prestazioni. Ricorda sempre, le eccezioni sono per casi eccezionali, non credere a nessuno che dica altrimenti o finirai con un thread github come quello!
gbjbaanb,

8

Non ho idea di cosa stia parlando quando dicono che sono lenti solo se vengono lanciati.

EDIT: Se non vengono generate eccezioni, significa che stai facendo una nuova eccezione () o qualcosa del genere. Altrimenti l'eccezione provocherà la sospensione del thread e la camminata dello stack. Questo può essere OK in situazioni più piccole, ma nei siti Web ad alto traffico, fare affidamento su eccezioni come un flusso di lavoro o meccanismo di percorso di esecuzione causerà sicuramente problemi di prestazioni. Le eccezioni, di per sé, non sono male e sono utili per esprimere condizioni eccezionali

Il flusso di lavoro delle eccezioni in un'app .NET utilizza eccezioni di prima e seconda possibilità. Per tutte le eccezioni, anche se le si sta rilevando e gestendo, l'oggetto di eccezione viene comunque creato e il framework deve ancora camminare nello stack per cercare un gestore. Se prendi e ripeti naturalmente, ciò richiederà più tempo: otterrai un'eccezione alla prima possibilità, prendila, ripeti, provocando un'altra eccezione alla prima possibilità, che quindi non trova un gestore, che quindi causa un'eccezione di seconda possibilità.

Le eccezioni sono anche oggetti nell'heap, quindi se stai generando tonnellate di eccezioni, stai causando problemi di prestazioni e memoria.

Inoltre, secondo la mia copia di "Performance Testing Microsoft .NET Web Applications" scritta dal team ACE:

"La gestione delle eccezioni è costosa. L'esecuzione del thread coinvolto viene sospesa mentre CLR ricorre attraverso lo stack di chiamate alla ricerca del gestore di eccezioni corretto e, quando viene trovato, il gestore di eccezioni e un certo numero di blocchi infine devono avere tutte la possibilità di eseguire prima di poter eseguire l'elaborazione regolare ".

La mia esperienza sul campo ha dimostrato che ridurre le eccezioni ha contribuito in modo significativo alle prestazioni. Ovviamente, ci sono altre cose da prendere in considerazione durante il test delle prestazioni, ad esempio se il tuo I / O su disco viene girato o le tue domande sono in pochi secondi, allora questo dovrebbe essere il tuo focus. Ma trovare e rimuovere le eccezioni dovrebbe essere una parte vitale di tale strategia.


1
Nulla di ciò che hai scritto contraddice l'affermazione che le eccezioni sono lente solo se vengono lanciate. Hai parlato solo di situazioni in cui vengono lanciate. Quando hai "aiutato in modo significativo le prestazioni" rimuovendo le eccezioni: 1) Erano vere condizioni di errore o solo errori dell'utente ?
Jon Skeet,

2) Stavi correndo con il debugger o no?
Jon Skeet,

L'unica cosa possibile che puoi fare con un'eccezione se non lanciarla è crearla come oggetto, che non ha senso. Essere sotto il debugger o no non importa - sarà ancora più lento. Sì, ci sono hook che accadranno con un debugger collegato, ma è ancora lento
Cory Foy,

4
Lo so: facevo parte del team Premier di MSFT. :) Diciamo solo un sacco - migliaia al secondo in alcuni casi estremi che abbiamo visto. Niente come connettersi con un debugger dal vivo e vedere solo le eccezioni più velocemente che si potrebbe leggere. Gli ex sono lenti - così si connette a un DB, quindi lo fai quando ha senso.
Cory Foy,

5
Cory, penso che il punto di "solo lento quando vengono lanciati" è che non devi preoccuparti delle prestazioni a causa della semplice presenza di blocchi di cattura / finalmente. Cioè questi di per sé non causano un calo delle prestazioni, ma solo il verificarsi di un'istanza effettiva dell'eccezione.
Ian Horwill,

6

L'argomento che ho capito non è che il lancio di eccezioni sia negativo, ma di per sé lento. Si tratta invece di utilizzare il costrutto throw / catch come un modo di prima classe per controllare la normale logica dell'applicazione, anziché costrutti condizionali più tradizionali.

Spesso nella normale logica dell'applicazione si esegue un ciclo in cui la stessa azione viene ripetuta migliaia / milioni di volte. In questo caso, con una profilazione molto semplice (vedi la classe Cronometro), puoi vedere di persona che lanciare un'eccezione invece di dire una semplice istruzione if può risultare sostanzialmente più lenta.

In effetti, una volta ho letto che il team .NET di Microsoft ha introdotto i metodi TryXXXXX in .NET 2.0 a molti dei tipi di FCL di base in particolare perché i clienti si lamentavano che le prestazioni delle loro applicazioni erano così lente.

Si scopre che in molti casi ciò è dovuto al fatto che i clienti stavano tentando la conversione del tipo di valori in un ciclo e ogni tentativo è fallito. Un'eccezione di conversione è stata generata e quindi catturata da un gestore di eccezioni che ha ingoiato l'eccezione e ha continuato il ciclo.

Microsoft ora consiglia di utilizzare i metodi TryXXX in particolare in questa situazione per evitare tali possibili problemi di prestazioni.

Potrei sbagliarmi, ma sembra che tu non sia sicuro della veridicità dei "benchmark" di cui hai letto. Soluzione semplice: provalo tu stesso.


Pensavo che anche internamente quelle funzioni "provare" usassero eccezioni?
Greg

1
Queste funzioni "Prova" non generano eccezioni internamente per un errore nell'analisi del valore di input. Tuttavia generano ancora eccezioni per altre situazioni di errore, come ArgumentException.
Ash,

Penso che questa risposta si avvicini al cuore del problema rispetto a qualsiasi altra. Dire "usa le eccezioni solo in circostanze ragionevoli" non risponde davvero alla domanda - la vera intuizione è che l'uso delle eccezioni C # per il flusso di controllo è molto più lento dei soliti costrutti condizionali. Potresti essere perdonato per aver pensato diversamente. In OCaml, le eccezioni sono più o meno un GOTO e il modo accettato di implementare l' interruzione quando si utilizzano le funzionalità imperative. Nel mio caso particolare, la sostituzione in un ciclo stretto int.Parse () più try / catch vs. int. TryParse () ha dato un notevole aumento delle prestazioni.
Hugh W,

4

Il mio server XMPP ha ottenuto un notevole aumento di velocità (scusate, nessun numero reale, puramente osservativo) dopo che ho costantemente cercato di impedire che si verificassero (come verificare se un socket è collegato prima di provare a leggere più dati) e darmi modi per evitarli (i metodi TryX menzionati). Questo era solo con circa 50 utenti virtuali attivi (in chat).


3
I numeri sarebbero utili, sfortunatamente :( Le cose come le operazioni sui socket dovrebbero superare di gran lunga i costi delle eccezioni, certamente quando non eseguono il debug. Se mai lo esegui un benchmark completo, sarei davvero interessato a vedere i risultati.
Jon Skeet,

3

Solo per aggiungere la mia recente esperienza a questa discussione: in linea con la maggior parte di ciò che è scritto sopra, ho trovato che lanciare eccezioni è estremamente lento se fatto su una base ripetuta, anche senza il debugger in esecuzione. Ho appena aumentato le prestazioni di un programma di grandi dimensioni che sto scrivendo del 60% modificando circa cinque righe di codice: passare a un modello di codice di ritorno anziché generare eccezioni. Certo, il codice in questione era in esecuzione migliaia di volte e potenzialmente generava migliaia di eccezioni prima che lo cambiassi. Quindi sono d'accordo con l'affermazione di cui sopra: generare eccezioni quando qualcosa di importante in realtà va storto, non come un modo per controllare il flusso dell'applicazione in situazioni "previste".


2

Se li confronti per restituire i codici, sono lenti come l'inferno. Tuttavia, come indicato nei poster precedenti, non si desidera avviare il normale funzionamento del programma, quindi si ottiene il colpo perfetto solo quando si verifica un problema e nella stragrande maggioranza dei casi le prestazioni non contano più (poiché l'eccezione implica comunque un blocco stradale).

Vale sicuramente la pena utilizzare oltre i codici di errore, i vantaggi sono enormi IMO.


2

Non ho mai avuto problemi di prestazioni con le eccezioni. Uso molto le eccezioni: non posso mai usare i codici di ritorno se posso. Sono una cattiva pratica e, secondo me, odorano di codice spaghetti.

Penso che tutto si riduca al modo in cui usi le eccezioni: se le usi come codici di ritorno (ogni chiamata di metodo nello stack cattura e ricomincia da capo), allora, sì, saranno lenti, perché hai un overhead per ogni singola cattura / lancio.

Ma se lanci in fondo alla pila e prendi in cima (sostituisci un'intera catena di codici di ritorno con un lancio / cattura), tutte le operazioni costose vengono eseguite una volta.

Alla fine, sono una funzione linguistica valida.

Solo per dimostrare il mio punto

Si prega di eseguire il codice a questo link (troppo grande per una risposta).

Risultati sul mio computer:

marco@sklivvz:~/develop/test$ mono Exceptions.exe | grep PM
10/2/2008 2:53:32 PM
10/2/2008 2:53:42 PM
10/2/2008 2:53:52 PM

I timestamp vengono emessi all'inizio, tra codici di ritorno ed eccezioni, alla fine. Ci vuole lo stesso tempo in entrambi i casi. Nota che devi compilare con ottimizzazioni.


2

Ma mono genera un'eccezione 10 volte più veloce della modalità standalone .net e la modalità autonoma .net genera un'eccezione 60 volte più veloce della modalità debugger .net. (Le macchine di prova hanno lo stesso modello di CPU)

int c = 1000000;
int s = Environment.TickCount;
for (int i = 0; i < c; i++)
{
    try { throw new Exception(); }
    catch { }
}
int d = Environment.TickCount - s;

Console.WriteLine(d + "ms / " + c + " exceptions");

1

In modalità di rilascio l'overhead è minimo.

A meno che non si utilizzino eccezioni per il controllo del flusso (ad esempio, uscite non locali) in modo ricorsivo, dubito che sarete in grado di notare la differenza.


1

Sul CLR di Windows, per una catena di chiamate di profondità 8, generare un'eccezione è 750 volte più lento del controllo e della propagazione di un valore di ritorno. (vedi sotto per i benchmark)

Questo costo elevato per le eccezioni è dovuto al fatto che il CLR di Windows si integra con qualcosa chiamato Gestione delle eccezioni strutturata di Windows . Ciò consente alle eccezioni di essere correttamente catturate e lanciate in diversi runtime e lingue. Tuttavia, è molto molto lento.

Le eccezioni nel runtime Mono (su qualsiasi piattaforma) sono molto più veloci, perché non si integrano con SEH. Tuttavia, si verifica una perdita di funzionalità durante il passaggio di eccezioni tra più runtime perché non utilizza nulla come SEH.

Ecco i risultati abbreviati dal mio benchmark di eccezioni vs valori di ritorno per il CLR di Windows.

baseline: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.25 (0), time elapsed 13.0007 ms
baseline: recurse_depth 8, error_freqeuncy 0.5 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 0.75 (0), time elapsed 13.0008 ms
baseline: recurse_depth 8, error_freqeuncy 1 (0), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0 (0), time elapsed 13.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.25 (249999), time elapsed 14.0008 ms
retval_error: recurse_depth 5, error_freqeuncy 0.5 (499999), time elapsed 16.0009 ms
retval_error: recurse_depth 5, error_freqeuncy 0.75 (999999), time elapsed 16.001 ms
retval_error: recurse_depth 5, error_freqeuncy 1 (999999), time elapsed 16.0009 ms
retval_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 20.0011 ms
retval_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 21.0012 ms
retval_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 24.0014 ms
retval_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 24.0013 ms
exception_error: recurse_depth 8, error_freqeuncy 0 (0), time elapsed 31.0017 ms
exception_error: recurse_depth 8, error_freqeuncy 0.25 (249999), time elapsed 5607.3208     ms
exception_error: recurse_depth 8, error_freqeuncy 0.5 (499999), time elapsed 11172.639  ms
exception_error: recurse_depth 8, error_freqeuncy 0.75 (999999), time elapsed 22297.2753 ms
exception_error: recurse_depth 8, error_freqeuncy 1 (999999), time elapsed 22102.2641 ms

Ed ecco il codice ..

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

public class TestIt {
    int value;

    public class TestException : Exception { } 

    public int getValue() {
        return value;
    }

    public void reset() {
        value = 0;
    }

    public bool baseline_null(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            return shouldfail;
        } else {
            return baseline_null(shouldfail,recurse_depth-1);
        }
    }

    public bool retval_error(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                return false;
            } else {
                return true;
            }
        } else {
            bool nested_error = retval_error(shouldfail,recurse_depth-1);
            if (nested_error) {
                return true;
            } else {
                return false;
            }
        }
    }

    public void exception_error(bool shouldfail, int recurse_depth) {
        if (recurse_depth <= 0) {
            if (shouldfail) {
                throw new TestException();
            }
        } else {
            exception_error(shouldfail,recurse_depth-1);
        }

    }

    public static void Main(String[] args) {
        int i;
        long l;
        TestIt t = new TestIt();
        int failures;

        int ITERATION_COUNT = 1000000;


        // (0) baseline null workload
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    t.baseline_null(shoulderror,recurse_depth);
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "baseline: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));
            }
        }


        // (1) retval_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    if (!t.retval_error(shoulderror,recurse_depth)) {
                        failures++;
                    }
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "retval_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));
            }
        }

        // (2) exception_error
        for (int recurse_depth = 2; recurse_depth <= 10; recurse_depth+=3) {
            for (float exception_freq = 0.0f; exception_freq <= 1.0f; exception_freq += 0.25f) {            
                int EXCEPTION_MOD = (exception_freq == 0.0f) ? ITERATION_COUNT+1 : (int)(1.0f / exception_freq);            

                failures = 0;
                DateTime start_time = DateTime.Now;
                t.reset();              
                for (i = 1; i < ITERATION_COUNT; i++) {
                    bool shoulderror = (i % EXCEPTION_MOD) == 0;
                    try {
                        t.exception_error(shoulderror,recurse_depth);
                    } catch (TestException e) {
                        failures++;
                    }
                }
                double elapsed_time = (DateTime.Now - start_time).TotalMilliseconds;
                Console.WriteLine(
                    String.Format(
                      "exception_error: recurse_depth {0}, error_freqeuncy {1} ({2}), time elapsed {3} ms",
                        recurse_depth, exception_freq, failures,elapsed_time));         }
        }
    }
}


}

5
Oltre a perdere il punto della domanda, non utilizzare DateTime.Now per i benchmark: utilizzare il cronometro, progettato per misurare il tempo trascorso. Non dovrebbe essere un problema qui perché stai misurando periodi di tempo ragionevolmente lunghi ma vale la pena prendere l'abitudine.
Jon Skeet,

Al contrario, la domanda è "sono eccezioni lente", punto. Ha specificamente chiesto di evitare l'argomento di quando lanciare eccezioni, perché quell'argomento oscura i fatti. Quali sono le prestazioni delle eccezioni?
David Jeske,

0

Una breve nota qui sulle prestazioni associate alla cattura di eccezioni.

Quando il percorso di esecuzione entra in un blocco 'prova', non accade nulla di magico. Non ci sono istruzioni "try" e nessun costo associato all'ingresso o all'uscita dal blocco try. Le informazioni sul blocco try sono archiviate nei metadati del metodo e questi metadati vengono utilizzati in fase di esecuzione ogni volta che viene sollevata un'eccezione. Il motore di esecuzione cammina nello stack alla ricerca della prima chiamata contenuta in un blocco try. Qualsiasi sovraccarico associato alla gestione delle eccezioni si verifica solo quando vengono generate eccezioni.


1
Tuttavia, la presenza di eccezioni può influire sull'ottimizzazione: i metodi con gestori di eccezioni espliciti sono più difficili da incorporare e il riordinamento delle istruzioni è limitato da essi.
Eamon Nerbonne,

-1

Quando si scrivono classi / funzioni che gli altri possono usare, sembra difficile dire quando le eccezioni sono appropriate. Ci sono alcune parti utili di BCL che ho dovuto abbandonare e cercare pinvoke perché generano eccezioni invece di restituire errori. In alcuni casi è possibile aggirare il problema, ma per altri come System.Management e Performance Counter ci sono usi in cui è necessario eseguire loop in cui le eccezioni vengono generate frequentemente da BCL.

Se stai scrivendo una libreria e c'è una remota possibilità che la tua funzione possa essere utilizzata in un ciclo e c'è un potenziale per una grande quantità di iterazioni, usa il modello Try .. o in qualche altro modo per esporre gli errori oltre alle eccezioni. E anche allora, è difficile dire quanto verrà chiamata la tua funzione se viene utilizzata da molti processi in ambiente condiviso.

Nel mio codice, le eccezioni vengono generate solo quando le cose sono così eccezionali che è necessario andare a guardare la traccia dello stack e vedere cosa è andato storto e quindi risolverlo. Quindi ho praticamente riscritto parti di BCL per utilizzare la gestione degli errori basata sul modello Try .. anziché sulle eccezioni.


2
Questo non sembra corrispondere all'affermazione del poster " Non voglio discutere su quando e non gettare eccezioni ".
hrbrmstr,
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.