Sdílet prostřednictvím


Průvodce pro začátečníky pro optimalizaci kódu a snížení nákladů na výpočetní prostředky (C#, Visual Basic, C++, F#)

Snížení výpočetní doby znamená snížení nákladů, takže optimalizace kódu může ušetřit peníze. V tomto článku si ukážeme, jak můžete pomocí různých nástrojů pro profilaci tuto úlohu dosáhnout.

Místo poskytování podrobných pokynů je zde záměr ukázat vám, jak efektivně používat nástroje pro profilaci a jak interpretovat data. Nástroj Využití procesoru vám může pomoct zachytit a vizualizovat, kde se ve vaší aplikaci používají výpočetní prostředky. Zobrazení využití procesoru, jako je strom volání a graf plamene, poskytují pěknou grafickou vizualizaci místa stráveného časem ve vaší aplikaci. Kromě toho může automatické přehledy zobrazovat přesné optimalizace, které můžou mít velký dopad. Další nástroje pro profilaci vám také můžou pomoct izolovat problémy. Chcete-li porovnat nástroje, podívejte se, který nástroj mám zvolit?

Zahájení šetření

  • Začněte vyšetřování tím, že použijete trasování využití procesoru. Nástroj Využití procesoru je často užitečný k zahájení šetření výkonu a optimalizaci kódu pro snížení nákladů.
  • Pokud chcete další přehledy, které vám pomůžou izolovat problémy nebo zlepšit výkon, zvažte shromažďování trasování pomocí některého z dalších nástrojů pro profilaci. Příklad:
    • Podívejte se na využití paměti. V případě .NET nejprve vyzkoušejte nástroj pro přidělování objektů .NET. V případě .NET nebo C++ se můžete podívat na nástroj Využití paměti.
    • Pokud vaše aplikace používá vstupně-výstupní operace souboru, použijte nástroj Pro vstupně-výstupní operace souboru.
    • Pokud používáte ADO.NET nebo Entity Framework, můžete zkusit databázový nástroj prozkoumat dotazy SQL, přesný čas dotazu atd.

Příklad shromažďování dat

Ukázkové snímky obrazovky zobrazené v tomto článku jsou založené na aplikaci .NET, která spouští dotazy na databázi blogů a přidružených blogových příspěvků. Nejprve prozkoumáte trasování využití procesoru a vyhledáte příležitosti k optimalizaci kódu a snížení nákladů na výpočetní prostředky. Po získání obecné představy o tom, co se děje, se také podíváte na trasování z jiných nástrojů pro profilaci, které pomáhají izolovat problémy.

Shromažďování dat vyžaduje následující kroky (tady se nezobrazuje):

  • Nastavení aplikace na build vydané verze
  • V profileru výkonu (Alt+F2) vyberte nástroj Využití procesoru. (Další kroky zahrnují několik dalších nástrojů.)
  • V profileru výkonu spusťte aplikaci a shromážděte trasování.

Kontrola oblastí vysokého využití procesoru

Začněte shromažďováním trasování pomocí nástroje Využití procesoru. Při načtení diagnostických dat nejprve zkontrolujte počáteční stránku sestavy .diagsession, která zobrazuje horní Přehledy a horká cesta. Horká cesta zobrazuje cestu kódu s nejvyšším využitím procesoru ve vaší aplikaci. Tyto části můžou obsahovat tipy, které vám pomůžou rychle identifikovat problémy s výkonem, které můžete vylepšit.

Můžete také zobrazit horká cesta v zobrazení Stromu volání. Pokud chcete toto zobrazení otevřít, použijte odkaz Otevřít podrobnosti v sestavě a pak vyberte Strom volání.

V tomto zobrazení se znovu zobrazí horká cesta, která ukazuje vysoké využití procesoru pro GetBlogTitleX metodu v aplikaci pomocí přibližně 60% podílu využití procesoru aplikace. Hodnota GetBlogTitleX vlastního procesoruje ale nízká, pouze přibližně 0,10 %. Na rozdíl od celkového využití procesoru vyloučí hodnota vlastního procesoru čas strávený v jiných funkcích, takže víme, že se podíváme dál dolů v zobrazení Stromu volání pro skutečný kritický bod.

Snímek obrazovky se stromem volání v nástroji Využití procesoru

GetBlogTitleX provádí externí volání dvou knihoven LINQ DLL, které využívají většinu času procesoru, což je důkazem velmi vysokých hodnot self cpu . Toto je první vodítko, které může být vhodné vyhledat dotaz LINQ jako oblast pro optimalizaci.

Snímek obrazovky se zobrazením Stromu volání v nástroji Využití procesoru se zvýrazněným vlastním procesorem

Pokud chcete získat vizualizovaný strom volání a jiné zobrazení dat, přepněte do zobrazení Flame Graph (vyberte ze stejného seznamu jako strom volání). Opět to vypadá, že GetBlogTitleX metoda odpovídá za velké množství využití procesoru aplikace (znázorněno žlutě). Externí volání knihoven DLL LINQ se zobrazí pod GetBlogTitleX polem a používají pro metodu veškerý čas procesoru.

Snímek obrazovky se zobrazením Flame Graph v nástroji Využití procesoru

Shromažďování dalších dat

Další nástroje můžou často poskytovat další informace, které vám pomůžou s analýzou a izolovat problém. V tomto příkladu se podíváme na následující přístup:

  • Nejprve se podíváme na využití paměti. Může existovat korelace mezi vysokým využitím procesoru a vysokým využitím paměti, takže může být užitečné se podívat na obojí, abyste problém izolovali.
  • Vzhledem k tomu, že jsme identifikovali knihovny DLL LINQ, podíváme se také na nástroj Databáze.

Kontrola využití paměti

Pokud chcete zjistit, co se děje s aplikací z hlediska využití paměti, shromážděte trasování pomocí nástroje pro přidělování objektů .NET (V jazyce C++ použijte místo toho nástroj Využití paměti). Zobrazení Stromu volání v trasování paměti zobrazuje horkou cestu a pomáhá identifikovat oblast vysokého využití paměti. V tomto okamžiku GetBlogTitleX se zdá, že metoda generuje velké množství objektů! Ve skutečnosti bylo přiděleno více než 900 000 objektů.

Snímek obrazovky se zobrazením stromu volání v nástroji pro přidělování objektů .NET

Většina vytvořených objektů je řetězce, pole objektů a int32. Možná budete moct zjistit, jak se tyto typy generují prozkoumáním zdrojového kódu.

Kontrola dotazu v nástroji Databáze

Můžete vybrat vícenásobný výběr databázového nástroje spolu s využitím procesoru. Po shromáždění trasování vyberte na stránce diagnostiky kartu Dotazy. Na kartě Dotazy pro trasování databáze uvidíte první řádek s nejdelším dotazem 2446 ms. Sloupec Záznamy ukazuje, kolik záznamů dotaz načte. Tyto informace můžeme použít k pozdějšímu porovnání.

Snímek obrazovky s databázovými dotazy v nástroji Database

Prozkoumáním SELECT příkazu vygenerovaného LINQ ve sloupci Query identifikujete první řádek jako dotaz přidružený k GetBlogTitleX metodě. Pokud chcete zobrazit celý řetězec dotazu, rozbalte šířku sloupce, pokud potřebujete. Úplný řetězec dotazu je:

SELECT "b"."Url", "b"."BlogId", "p"."PostId", "p"."Author", "p"."BlogId", "p"."Content", "p"."Date", "p"."MetaData", "p"."Title"
FROM "Blogs" AS "b" LEFT JOIN "Posts" AS "p" ON "b"."BlogId" = "p"."BlogId" ORDER BY "b"."BlogId"

Všimněte si, že tady načítáte velké množství hodnot sloupců, možná více, než potřebujete. Pojďme se podívat na zdrojový kód.

Optimalizace kódu

Je čas se podívat na GetBlogTitleX zdrojový kód. V nástroji Databáze klikněte pravým tlačítkem myši na dotaz a zvolte Přejít na zdrojový soubor. Ve zdrojovém kódu pro GetBlogTitleXnajdeme následující kód, který ke čtení databáze používá LINQ.

foreach (var blog in db.Blogs.Select(b => new { b.Url, b.Posts }).ToList())
  {
    foreach (var post in blog.Posts)
    {
      if (post.Author == "Fred Smith")
      {
        Console.WriteLine($"Post: {post.Title}");
      }
  }
}

Tento kód používá foreach smyčky k vyhledávání v databázi pro všechny blogy s "Fred Smith" jako autor. Když se na to podíváte, můžete vidět, že se v paměti generuje hodně objektů: nové pole objektů pro každý blog v databázi, přidružené řetězce pro každou adresu URL a hodnoty vlastností obsažených v příspěvcích, jako je ID blogu.

Provedete trochu průzkumu a najdete několik běžných doporučení pro optimalizaci dotazů LINQ a přijít s tímto kódem.

foreach (var x in db.Posts.Where(p => p.Author.Contains("Fred Smith")).Select(b => b.Title).ToList())
{
  Console.WriteLine("Post: " + x);
}

V tomto kódu jste provedli několik změn, které vám pomůžou optimalizovat dotaz:

  • Where Přidání klauzule a odstranění jedné ze foreach smyček.
  • Projected only the Title property in the Select statement, which is all you need in this example.

Pak znovu otestujte pomocí nástrojů pro profilaci.

Kontrola výsledků

Po aktualizaci kódu znovu spusťte nástroj Využití procesoru a shromážděte trasování. Zobrazení Stromu volání ukazuje, že GetBlogTitleX je spuštěno pouze 1754 ms, s využitím 37 % celkového využití procesoru aplikace, významné zlepšení z 59 %.

Snímek obrazovky s vylepšeným využitím procesoru v zobrazení stromu volání nástroje Využití procesoru

Přepněte do zobrazení Flame Graph a zobrazte další vizualizaci vylepšení. V tomto zobrazení GetBlogTitleX také používá menší část procesoru.

Snímek obrazovky s vylepšeným využitím procesoru v zobrazení Flame Graph nástroje Využití procesoru

Zkontrolujte výsledky v trasování databázového nástroje a pomocí tohoto dotazu se čtou jenom dva záznamy místo 100 000! Dotaz je také hodně zjednodušený a eliminuje nepotřebné funkce LEFT JOIN, která byla vygenerována dříve.

Snímek obrazovky s rychlejším časem dotazu v nástroji Databáze

V dalším kroku znovu zkontrolujte výsledky v nástroji pro přidělování objektů .NET a podívejte se, že GetBlogTitleX je zodpovědný pouze za 56 000 přidělení objektů, téměř 95% snížení z 900 000!

Snímek obrazovky s omezenými přiděleními paměti v nástroji pro přidělování objektů .NET

Iterovat

Může být potřeba několik optimalizací a můžete pokračovat iterací se změnami kódu, abyste viděli, které změny zlepšují výkon a snižují náklady na výpočetní prostředky.

Další kroky

Následující blogové příspěvky obsahují další informace, které vám pomůžou efektivně používat nástroje pro měření výkonu sady Visual Studio.