Considerațiile privind performanța pentru aruncarea excepțiilor

Am întâlnit de mai multe ori tipul de cod următsauși mă întreb dacă este o practică bună (din perspectiva performanței) sau nu:

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);
}

Practic, ceea ce face coderul este că ele cuprind excepția într-o excepție personalizată și aruncând din nou acest lucru.

Cum diferă aceasta în Performanță de următoarele două:

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw ex;
}

sau

try
{
    ... // some code
}
catch (Exception ex)
{
    .. // Do something
    throw;
}

Putting aside any functional saucoding best practice arguments, is there any performance difference between the 3 approaches?

0
fr hi bn

8 răspunsuri

@Brad Tutterow

Excepția nu se pierde în primul caz, ci este transmisă constructorului. Cu toate acestea, voi fi de acord cu restul dvs., a doua abordare este o idee foarte proastă din cauza pierderii urmei. Când am lucrat cu .NET, am fugit în multe cazuri în care alți programatori au făcut asta, și m-au frustrat fără sfârșit atunci când aveam nevoie să văd adevărata cauză a unei excepții, doar pentru a găsi că este redus de la un bloc de încercare uriaș Acum nu am nici o idee în legătură cu originea problemei.

De asemenea, am comentat comentariul lui Brad că nu trebuie să vă faceți griji cu privire la spectacol. Acest tip de optimizare micro este o idee HORRIBLE. Cu excepția cazului în care vorbești despre aruncarea unei excepții în fiecare iterație a unui buclă pentru care se execută o perioadă lungă de timp, probabil că nu te vei întâlni în probleme de performanță prin modul de utilizare excepțional.

Optimizați întotdeauna performanța atunci când aveți valori care indică faptul că este necesar să optimizați performanța și apoi loviți petele care s-au dovedit a fi vinovat.

Este mult mai bine să aveți un cod care poate fi citit, cu capacități ușoare de depanare (IE nu ascunde urmărirea stivei), decât să facă ceva să ruleze mai repede o nanosecundă.

O notă finală despre împachetarea excepțiilor într-o excepție particularizată ... aceasta poate fi o construcție foarte utilă, mai ales atunci când se ocupă de UI-uri. Puteți încheia orice caz excepțional cunoscut și rezonabil într-o excepție personalizată de bază (sau una care se extinde de la excepția de bază menționată), iar apoi utilizatorul poate captura doar această excepție de bază. Când este capturat, excepția va trebui să furnizeze mijloacele de afișare a informațiilor către utilizator, să spună o proprietate ReadableMessage sau ceva de-a lungul acestor linii. Astfel, ori de câte ori UI ratează o excepție, este din cauza unei erori pe care trebuie să o remediați și oricând captează o excepție, este o condiție de eroare cunoscută care poate și ar trebui să fie gestionată corespunzător de interfața utilizator.

0
adăugat

Ca și David, cred că al doilea și al treilea performează mai bine. Dar oricare dintre cei trei ar face destul de prost să-și petreacă timpul îngrijorându-se? Cred că există probleme mai mari decât să vă faceți griji.

FxCop recomandă întotdeauna cea de-a treia abordare peste cea de-a doua, astfel încât urmărirea inițială a stivei să nu se piardă.

Editare: Au fost eliminate lucruri care nu prea aveau dreptate și Mike a fost destul de amabil să sublinieze.

0
adăugat

Aruncarea în primul dvs. exemplu are sarcina de a crea un nou obiect CustomException.

Re-aruncarea în cel de-al doilea exemplu va arunca o excepție de tip Excepție.

Re-aruncarea în cel de-al treilea exemplu va arunca o excepție de același tip care a fost aruncată de "unii cod".

Așadar, exemplele 2 și 3 utilizează mai puține resurse.

0
adăugat

Evident, vă supuneți pedeapsa de a crea obiecte noi (noua excepție), așa cum faceți cu fiecare linie de cod pe care o adăugați la programul dvs., trebuie să decideți dacă o categorie mai bună a excepțiilor plătește pentru munca suplimentară.

Ca o sfat pentru a lua această decizie, dacă noile obiecte nu conțin informații suplimentare despre excepție, atunci puteți uita construirea de noi excepții.

Cu toate acestea, în alte circumstanțe, având o ierarhie de excepții este foarte convenabilă pentru utilizatorul clasei dvs. Să presupunem că implementați modelul de fațadă, nici unul dintre scenariile considerate până acum nu este bun:

  1. nu este bine să ridicați fiecare excepție ca obiect Excepție deoarece pierdeți (probabil) informații valoroase
  2. nu este bun nici să ridici orice fel de obiect pe care îl prindă pentru că nu reușești să faci fațada

În acest caz ipotetic, este mai bine să creați o ierarhie de clase de excepție care, abstractizând utilizatorii dvs. de complexitatea interioară a sistemului, le permite să știe ceva despre tipul de excepție produs.

Ca notă laterală:

Eu personal nu îmi place să folosesc excepțiile (ierarhiile de clase derivate din clasa Excepție) pentru a implementa logica. Ca în cazul:

try {
        // something that will raise an exception almost half the time
} catch( InsufficientFunds e) {
        // Inform the customer is broke
} catch( UnknownAccount e ) {
        // Ask for a new account number
}
0
adăugat

Din punct de vedere pur de performanță, cred că cel de-al treilea caz este cel mai performant. Ceilalți doi trebuie să extragă o urmă de stivă și să construiască obiecte noi, ambele fiind potențial destul de consumatoare de timp.

Având în vedere că aceste trei blocuri de cod au comportamente diferite (externe) foarte , compararea lor este ca și cum ar fi întrebat dacă QuickSort este mai eficient decât adăugarea unui element la un copac rosu-negru. Nu este la fel de important ca alegerea unui lucru bun.

0
adăugat

După cum au afirmat și ceilalți, cea mai bună performanță vine din partea inferioară, din moment ce vă răsturnați doar un obiect existent. Cel de mijloc este cel puțin corect deoarece pierde teancul.

Eu personal folosesc excepții personalizate dacă vreau să decuple anumite dependențe în cod. De exemplu, am o metodă care încarcă date dintr-un fișier XML. Acest lucru poate merge prost în multe moduri diferite.

S-ar putea să nu reușească să citească de pe disc (FileIOException), utilizatorul ar putea încerca să-l acceseze de undeva unde nu este permis (SecurityException), fișierul ar putea fi corupt (XmlParseException), datele ar putea fi în format greșit (DeserialisationException).

În acest caz, astfel încât să fie mai ușor pentru clasa apelant să înțeleagă toate acestea, toate aceste excepții răstoarnă o singură excepție personalizată (FileOperationException), astfel că apelantul nu are nevoie de referințe la System.IO sau System.Xml, dar poate încă accesați ce eroare a avut loc printr-un enum și orice informații importante.

După cum sa spus, nu încercați să optimizați micro-așa ceva, actul de a arunca o excepție la toate este cel mai lent lucru care apare aici. Cea mai bună îmbunătățire este să încerci să eviți o excepție.

public bool Load(string filepath)
{
  if (File.Exists(filepath)) //Avoid throwing by checking state
  {
    //Wrap anyways in case something changes between check and operation
    try { .... }
    catch (IOException ioFault) { .... }
    catch (OtherException otherFault) { .... }
    return true; //Inform caller of success
  }
  else { return false; } //Inform caller of failure due to state
}
0
adăugat

Nu faceți:

try
{
    // some code
}
catch (Exception ex) { throw ex; }

Deoarece aceasta va pierde urmărirea stivei.

În schimb, faceți:

try
{
    // some code
}
catch (Exception ex) { throw; }

Numai aruncarea va face, trebuie doar să treci variabila de excepție dacă vrei să fie excepția internă pe o nouă excepție personalizată.

0
adăugat
Punct bun - Mi-a lipsit asta în copia-pastă.
adăugat autor Keith, sursa
Adăugare mică - eliminați ex-ul, în caz contrar, creați avertizare variabilă neutilizată. încercați {// un cod} captură (excepție) {aruncați; }
adăugat autor Dennis, sursa

Așteptați ... de ce ne pasă de performanță dacă este aruncată o excepție? Cu excepția cazului în care folosim excepții ca parte a fluxului normal de aplicații (care este WAYYYY împotriva celor mai bune practici).

Am văzut doar cerințe de performanță în ceea ce privește succesul, dar niciodată în ceea ce privește eșecul.

0
adăugat