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

Ó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 thoughts on “.NET teljesítményhangolási tapasztalatok 4.

  1. Sipos Tamás

    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.

  2. KRis

    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

  3. SebDani

    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á…

  4. Pingback: Enum.TryParse - Molnár Gergő szakmai blogja - devPortal

Comments are closed.