databájt 2010.07.15. 15:44

How NOT to use string.Format

 Jó napot, jó kódolást! 

Egy ideje érik egy elhatározásom, hogy megosztok néhány tapasztalatot a hatékony kódolásról. 

Azért, mert mindig azt hallom vissza, hogy lassú a szoftverünk.
Azért, mert nem feltétlenül tudjuk, hogyan működik belülről drága jó Májkrokosztunk .NET keretrendszere.
Azért, mert mindig tanulhatunk a jó példából. 

Először is, mitől gyors egy program? Hát attól, hogy NEM  PA-ZA-ROL. Bővebben, nem szórja az erőforrásokat a négy égtáj felé könnyü pipafüstöt eregetve közben, elektronokat számolgatva. 

Na, akkor lássunk egy metódust, aminek a belseje (a foreach blokk) több, mint 13000-szer fut le (hogy miért, nem lényeges):


internal static Dictionary<string, TableDefDescriptor> GetDescriptorTables()
{
      var descriptorTables = new Dictionary<string, TableDefDescriptor>(); 

      foreach (var  kvP in MetadataManager.FlatProperties)
      {
            if (!kvP.Value.TableName.ToUpper().StartsWith("ALL_"))
            {
                  string classID = kvP.Value.TableSchema + "_" + kvP.Value.TableName;
                  try
                  {
                        if (MetadataManager.FlatClasses[classID].IsDescriptor)
{
                             string tableName = string.Format("{0}_{1}", MetadataManager.FlatClasses[classID].Schema, MetadataManager.FlatClasses[classID].CoreTable);
 

                             if (!descriptorTables.ContainsKey(tableName))
                             {
                                   TableDefDescriptor tbl = new TableDefDescriptor(MetadataManager.FlatClasses[classID].Schema, MetadataManager.FlatClasses[classID].CoreTable, MetadataManager.FlatClasses[classID].CoreTableKey);

                                    if (kvP.Value.DescriptorInternal != null || kvP.Value.DescriptorExternal != null)
                                         tbl.AddQualifier(kvP.Value);
                                   descriptorTables.Add(tableName, tbl);
                             }
                             else
                             {
                                   if (kvP.Value.DescriptorInternal != null || kvP.Value.DescriptorExternal != null)
                                         descriptorTables[tableName].AddQualifier(kvP.Value);
                             }
                        }
                  }
                  catch (Exception)
                  {
                        throw;
                  }
            }
      }
       return descriptorTables;
}


 

A fenti kód nagyszerű.  Arra, hogy megnézzük rajta, mit NEM lenne szabad csinálni, ha gyors programra vágyunk. 

String.Format, avagy mire NE használjuk 

Konkatenálásra. Hát, röhögtetős a különsége a két, egyébiránt egyforma kimenetet produkáló sornak: 

string classID = string.Format("{0}_{1}", kvp.Value.TableSchema, kvp.Value.TableName); // Kb 15000 tick

string classID2 = kvP.Value.TableSchema + "_" + kvp.Value.TableName; // Kb 750 tick, 20x gyorsabb 

Azért, mert a string.Format() implementációja StringBuilder-t instanciál, formátumot parszol, hókusz-pókuszol, csirkecsontokat szór a földre az aktuális csillagállástól függően, miegymás.

A konkatenálás meg összefűzi a két szövegrészt. A fenti metódusban, mivel 13000 –szor fut le kb. a foreach-en belüli rész,

csak a konkatenáláson buktunk 185 250 000 ticket, azaz ~80ms alatt csináltuk meg, amihez elég ~4ms is. Jó, mi? J 

Dictionary, avagy hogyan NE használjuk 

A Dictionary faj, mint olyan, arra való, hogy gyorsan lehessen valamit előkaparni sok elem közül. Ezért van kulcsa, nem azért, hogy mindenféle olvasható (értsd: string) dolgokat használjunk kulcsnak.

De egy dologról semmiképp nem szabad megfeledkezni: minden lookup-nak ára van!

Számoljuk meg, hányszor keressük elő a fenti kódban ezt: MetadataManager.FlatClasses[classID] 

...

Igen, jól számoljátok, 6x, azaz hatszor. Vagyis 5x feleslegesen dolgozik a szerencsétlen mikroprucesszor.

A fenti metódus kb. így nézne ki, ha én írtam volna: 


internal static IDictionary<string, TableDefDescriptor> GetDescriptorTables()
{
       var descriptorTables = new Dictionary<string, TableDefDescriptor>();

      foreach (var  kvP in MetadataManager.FlatProperties)
      {
            if (!kvP.Value.TableName.ToUpper().StartsWith("ALL_"))
            {
                  string classID = kvP.Value.TableSchema + "_" + kvP.Value.TableName;
                   // A lényeg, hogy nem dobjuk el a már kikotort cuccost
                  PLClass plClass = MetadataManager.FlatClasses[classID];

                  try
                  {
                        if (plClass.IsDescriptor)
                        {
                             string tableName = plClass.Schema + "_" + plClass.CoreTable;

                             if (!descriptorTables.ContainsKey(tableName))
                             {
                                   TableDefDescriptor tbl = new TableDefDescriptor(plClass.Schema, plClass.CoreTable, plClass.CoreTableKey);
                                   if (kvP.Value.DescriptorInternal != null || kvP.Value.DescriptorExternal != null)
                                         tbl.AddQualifier(kvP.Value);
                                   descriptorTables.Add(tableName, tbl);
                             }
                             else
                             {
                                   if (kvP.Value.DescriptorInternal != null || kvP.Value.DescriptorExternal != null)
 descriptorTables[tableName].AddQualifier(kvP.Value);
                             }
                        }
                  }
                  catch (Exception)
                  {
                        throw;
                  }
            }
      }
      return descriptorTables;
}


 

A kettő között kb. annyi a különbség, mintha poénból ötször (5x!!!) visszadobnánk a tűt a kazalba. 

Konklúzió, ha van ilyen

 Röviden, csak áttekintő jelleggel:

  • String.Format-tal konkatenálni -> PATÁS
  • Dictionary lookup eredményét újra meg újra eldobni -> PATÁS

Szóval, ha azt szeretnétek, hogy legyen keret mindig WC papírra, új, puccos gépekre, meg székekre, amire mindenkinek volt egy grimasza, akkor kezdjétek el megfogadni az ilyen apróságokat.

Vagy lehet kódolni Kovácsné és Társa módszerrel, akkor viszont ne vegyetek tartós tejet.

Szólj hozzá!

A bejegyzés trackback címe:

https://dotnot.blog.hu/api/trackback/id/tr164295549

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása