Úvahy o výkonu pro vyvolání výjimek

hlasů
7

Jsem narazil na následující typ kódu mnoho časů, a zajímalo by mě, jestli je to dobré praxe (z pohledu výkonnosti), nebo ne:

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

V podstatě to, co kodér dělá, je, že jsou zahrnující výjimku vlastní výjimky a házet znovu.

Jak se to liší v inscenaci z následujících dvou:

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

nebo

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

Odhlédneme-li některý funkční nebo kódující argumenty dobré praxe, je nějaký rozdíl výkonu mezi 3 přístupy?

Položena 09/08/2008 v 21:01
zdroj uživatelem
V jiných jazycích...                            


8 odpovědí

hlasů
10

@Brad Tutterow

Výjimkou není ztraceno v prvním případě, to je předán v konstruktoru. Budu s vámi dohodnout na zbytek když druhý přístup je velmi špatný nápad, protože ztráty trasování zásobníku. Když jsem pracoval s .NET, jsem narazil na mnoho případů, kdy jiní programátoři dělali jen to, a to mě frustrovaný k žádnému konci, když jsem potřeboval vidět skutečnou příčinu výjimku, jen aby zjistil, že je rethrown z obrovského bloku try-li to nyní mám tušení, kde je problém vznikl.

Také jsem druhý Brad poznámka, že byste neměli starat o výkonu. Tento druh mikro optimalizace je hrozný nápad. Pokud hovoříme o vyvolání výjimky v každé iteraci smyčky for, který je spuštěn po dlouhou dobu, budete více než pravděpodobné, ne narazit na problémy s výkonem mimochodem svého využití výjimek.

Vždy optimalizovat výkon, když máte metriky, které naznačují, co potřebujete pro optimalizaci výkonu, a pak udeřil do míst, která jsou prokazatelně být viník.

Je mnohem lepší mít čitelný kód se snadným možnostmi ladění (IE neskrývá trasování zásobníku), spíše než aby něco spustit nanosekund rychleji.

Poslední poznámka o balení výjimky do vlastní výjimky ... to může být velmi užitečné konstrukt, a to zejména pokud se jedná o UIS. Můžete zabalit všechny známé a přiměřené výjimečný případ do jisté základna vlastní výjimku (nebo ten, který se rozprostírá od uvedené základny výjimka), a pak UI může jen zachytit tento základní výjimku. Když chytil, výjimka bude muset poskytnout prostředky pro zobrazování informací pro uživatele, řekněme vlastnost ReadableMessage, nebo něco podél těchto linek. Tedy kdykoliv UI mine výjimku, je to z důvodu chyby, které potřebujete opravit, a kdykoliv to zachytává výjimku, to je známá chyba, která může a musí být správně zpracována UI.

Odpovězeno 09/08/2008 v 22:17
zdroj uživatelem

hlasů
2

Nedělají:

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

Vzhledem k tomu, ztratí trasování zásobníku.

Místo toho je třeba:

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

Jen hod bude dělat, stačí předat proměnnou výjimku, pokud chcete, aby to bylo vnitřní výjimka na nové vlastní výjimky.

Odpovězeno 16/08/2008 v 15:24
zdroj uživatelem

hlasů
2

Zřejmě budete vynaložit trestu vytváření nových objektů (nová výjimka) ano, přesně tak, jak je tomu u každého řádku kódu, který připojíte do svého programu, musíte se rozhodnout, zda k lepšímu kategorizace výjimky platí za práci navíc.

Jako radu, aby toto rozhodnutí, je-li vaše nové objekty nejsou nést další informace o výjimky pak můžete zapomenout na výstavbu nové výjimky.

Nicméně, v jiných případech, které mají hierarchii výjimek je velmi výhodné pro uživatele ze svých tříd. Předpokládám, že jste se provádí fasádě vzor ani jeden z dosud považován scénářů je dobré:

  1. Není dobré, aby si zvýšit každou výjimku jako objekt výjimka, protože jste ztratili (pravděpodobně) cenné informace
  2. není dobré ani zvyšovat každý druh objektu, který chytit, protože tím jste selhává při vytváření fasády

V tomto hypotetickém případě, tím lépe to udělat, je vytvořit hierarchii tříd výjimkou toho, abstrahovat svým uživatelům z vnitřní složitosti systému, který jim umožňuje vědět něco o druhu výjimky produkoval.

Jako vedlejší poznámku:

Já osobně nelíbí používání výjimek (hierarchie tříd odvozených od třídy Exception) zavést logiku. Stejně jako v případě, že:

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
}
Odpovězeno 09/08/2008 v 22:01
zdroj uživatelem

hlasů
2

Podobně jako David, myslím, že druhý a třetí dosahují lepších výsledků. Ale to by některý ze tří provedení dost špatně trávit čas starostmi o tom? Myslím, že existují větší problémy než výkon bát.

FxCop vždy doporučuje třetí přístup přes druhou, takže se původní trasování zásobníku neztratí.

Edit: Odstraněno věci, které se prostě špatně a Mike byl tak laskav a poukázat.

Odpovězeno 09/08/2008 v 21:58
zdroj uživatelem

hlasů
1

Jak již bylo řečeno, nejlepší výkon pochází ze spodní jedné, protože jste právě Opětné vyvolání existující objekt. Prostřední z nich je alespoň správné, protože to ztrácí stoh papírů.

Já osobně používám vlastní výjimky, pokud chci oddělit určité závislosti v kódu. Například, mám metodu, která načítá data z XML souboru. To může jít v mnoha různými způsoby špatně.

To by mohlo selhat číst z disku (FileIOException), uživatel by se mohl pokusit se k nim dostat odněkud, kde nejsou povoleny (SecurityException), soubor může být poškozen (XmlParseException), data mohou být v nesprávném formátu (DeserialisationException).

V tomto případě, takže její snadnější pro třídu volající najít smysl toho všeho, všechny tyto výjimky znovu vyvolat jednostránkový vlastní výjimky (FileOperationException), takže to znamená, že volající nepotřebuje odkazy na System.IO nebo System.Xml, ale může ještě přístup k jaké došlo k chybě prostřednictvím výčtu a všechny důležité informace.

Jak již bylo uvedeno, nesnažte se micro-optimalizovat něco takového, akt házet výjimku vůbec je nejpomalejší věc, která se vyskytuje tady. Nejlepší zlepšení udělat, je pokusit se vyhnout výjimky vůbec.

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
}
Odpovězeno 10/08/2008 v 02:03
zdroj uživatelem

hlasů
0

Počkat .... proč se staráme o výkonu, pokud je vyvolána výjimka? Ledaže používáme výjimky jako součást normálního toku aplikace (což je WAYYYY proti osvědčených postupů).

Viděl jsem jen požadavky na výkon ve vztahu k úspěchu, ale nikdy ve vztahu k selhání.

Odpovězeno 30/09/2008 v 13:56
zdroj uživatelem

hlasů
0

Z čistě představení stand-bod Řekl bych, že třetí případ je velmi výkonný. Druzí dva muset extrahovat zásobníku-stopu a budovat nové objekty, z nichž oba jsou potenciálně poměrně časově náročné.

Který uvedl, že tyto tři bloky kódu mají velmi odlišné (externí) chování, takže jejich porovnávání je jako ptát se, zda QuickSort je účinnější než Přidání položky do červeno-černý strom. To není tak důležité jako výběr správné věci dělat.

Odpovězeno 10/08/2008 v 01:47
zdroj uživatelem

hlasů
0

Vhazování ve svém prvním příkladu má režii vytvoření nového CustomException objektu.

Re-throw ve svém druhém příkladu bude hodit výjimku typu výjimky.

Re-throw ve svém třetím příkladu bude hodit výjimku stejného typu, který byl vržen svého „kód“.

Takže druhý a třetí příklady používají méně zdrojů.

Odpovězeno 09/08/2008 v 21:50
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more