Soci (Soczó Zsolt) szakmai blogja

2009.02.05.

.NET teljesítményhangolási tapasztalatok 4.

Filed under: .NET,C#,Optimalizálás,Szakmai élet — Soczó Zsolt @ 11:26

Óvakodj az enumtól, mert lassú lészen az – áll a .NET bibliában.

Ártatlan kis jószágnak néz ki ez az enum, mégis sokszor láttam már, hogy miatta lassul be egy rendszer. Mi a lassú rajta? Minden. A Parsolás pl. De ez még érthető is. De hogy a ToString() is tetű, az már kevésbé. Sajnos azonban reflectiont használ ezekhez a műveletekhez, ami köztudottan lassú.
Szerencsére elég könnyű segíteni a baján. Ha Parsolni kell, azaz egy string alapján kell egy enum értéket megszülni, akkor ezt egyszerűen meg lehet oldani egy Dictionary-vel, ami string kulcsokkal és az konkrét enum értékekkel van feltöltve.
Most a másik oldalt mutatom meg, a turbó ToString()-et.
Egyszerű demó enumunk:

public enum TradeDirection
{
Short,
Long
}

Ebből tehát ha van egy példányunk amin ToString()-et hívunk, az lassú lesz. Hozzunk létre egy Dictionary-t, ami segít az enum-string asszociációban.

private static Dictionary tradeDirectionNames = new Dictionary();

Ezt kellene felölteni értékekkel. A C# generikus dolgaival szépen meg lehet ezt általánosan is fogalmazni, így mindenféle enumra működni fog:

tradeDirectionNames.FillEnumCache();

public static void FillEnumCache(this Dictionary enumNames)
{
foreach (T enumValue in Enum.GetValues(typeof(T)))
{
enumNames.Add(enumValue, enumValue.ToString());
}
}

Mivel extension methodként írtam meg olyan, mintha a Dictionary tudná ezt a funkciót, a T típusparamétert meg kitalálja a compiler, így nem kell kiírjam a teljes alakot:

tradeDirectionNames.FillEnumCache();

Hogy jogos-e erre az extension method az objektumorientált szempontból erősen vitatható, de nekem így kézre esett.

A generizálhatóság viszont szenzációs. Ezért imádom a C#-ot.

Miután a fenti megoldással gyorsítottam a rendszeren kiderült (profilerrel, mi mással), hogy egy összetett típusban ami két enumból állt lassú volt a GetHashCode implementációm, ami így nézett ki:

public override int GetHashCode()
{
return dir.GetHashCode() + zone.GetHashCode();
}

A dir és a zone egy-egy enum.

A gyorsításhoz így írtam át:

public override int GetHashCode()
{
return (int)dir << 4 + (int)zone; } [/source] Ez nem csak gyorsabb, de jobban is szór, mint az előző.

7 Comments

  1. Nekem azért furcsa ez, mert nekem pont ez tetszett annó a .NET-ben a Java-hoz képest, hogy rengeteg enum-ot használ!
    Ennek hatására kezdtem el én is erőteljesen használni Java-ban az enum-okat.
    Ezek után ha akad egy kis időm, majd én is ránézek profilerrel.

    Comment by Sipos Tamás — 2009.02.08. @ 22:44

  2. Kíváncsi vagyok mit látsz. Nekem ez már nem az első eset, hogy belefutok.

    Comment by Soczó Zsolt — 2009.02.08. @ 23:51

  3. Hello,

    Ennek az éremnek is két, de lehet hogy több, oldala van.

    Hányszor hallottam hogy fúúúúj string + string… helyette string.format, meg stringbuilder…

    Persze… igaz ha 1 millioszor kell ciklusban napi 100x ezt csinálni, vagy életek múlnak rajta…
    De ha nem akkor nem kell bit szintre lemenni…

    Ez a c# és a fejlett nyelvek lényege!!! Absztrakció… A problémával foglalkozunk, és nem a tényleges technikai megvalósítással.

    Tehát nem kell most rohanni és minden enum-t azonnal átírni, és a következő projektekben elő sem venni.
    Fel kell mérni, a helyzetet, és a szerint dolgozni. Mert lássuk be: az enumok megkönnyítik az életet : egyszerűsítenek, átláthatóbbá teszik a kódot, érthetőbbek, beszédesek…

    Ettől persze igaza van Socinak a fenti példában.
    De ilyet találunk minden mérnöki területen: követelmény-kényszer ill. fizikai/technikai ellentmondások területen…
    Kicsi legyen a telefonom bírja sokáig az aksi (nagyobb kell)

    Ez a szép… át kell hidalni :)

    Üdv,
    KRis

    Comment by KRis — 2009.02.10. @ 16:43

  4. Persze, ettől még nem dobtam ki én se az enumot, csak körbeprogramoztam ott, ahol lassú volt.

    Comment by Soczó Zsolt — 2009.02.10. @ 17:08

  5. Már majdnem azt hittem, hogy egy fricskát elengedhetek, hogy minek leprogramozni azt, amit a MS már megcsinált egyszer… ;-)
    De aztán rácsodálkoztam, hogy a System.ComponentModel.EnumConverter nem chache-el… :-( Pedig mindene megvan hozzá…

    Comment by SebDani — 2009.02.13. @ 16:04

  6. Természetesen: chache=cache vagy magyarosan: kessel

    Comment by SebDani — 2009.02.13. @ 16:05

  7. […] hogy az enum-sztring konverzió elég lassúcska, teljesítményérzékeny alkalmazásokban néha rá kell programoznunk, ha nem akarunk odaborostásodni a gép […]

    Pingback by Enum.TryParse - Molnár Gergő szakmai blogja - devPortal — 2010.01.08. @ 16:49

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress