All articles

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

Published 2009-02-05 - Last modified 2009-02-08

Original: https://soci.hu/blog/index.php/2009/02/05/net-teljesitmenyhangolasi-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ő.