.NET teljesítményhangolási tapasztalatok 4.
Thursday, February 5th, 2009Ó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<TradeDirection, string> tradeDirectionNames = new Dictionary<TradeDirection, string>();
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<T>(this Dictionary<T, string> 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<TradeDirection>.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;
}
Ez nem csak gyorsabb, de jobban is szór, mint az előző.
