Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Het optimaliseren van uw code vermindert de rekentijd en kosten. In deze casestudy ziet u hoe u Visual Studio-profileringshulpprogramma's gebruikt om prestatieproblemen in een .NET-voorbeeldtoepassing te identificeren en op te lossen. Als u profileringsprogramma's wilt vergelijken, raadpleegt u Welk hulpprogramma moet ik kiezen?
In deze handleiding wordt het volgende behandeld:
- Visual Studio-profileringshulpprogramma's gebruiken om de prestaties te analyseren en te verbeteren.
- Praktische strategieën voor het optimaliseren van CPU-gebruik, geheugentoewijzing en database-interacties.
Pas deze technieken toe om uw eigen toepassingen efficiënter te maken.
Optimalisatiestudie
De .NET-voorbeeldtoepassing voert query's uit op een SQLite-database met blogs en berichten met behulp van Entity Framework. Het voert veel query's uit en simuleert een praktijkscenario voor het ophalen van gegevens. De app is gebaseerd op het aan de slag-voorbeeld van Entity Framework, maar maakt gebruik van een grotere gegevensset.
Belangrijke prestatieproblemen zijn:
- Hoog CPU-gebruik: inefficiënte berekeningen of verwerkingstaken verhogen het CPU-verbruik en de kosten.
- Inefficiënte geheugentoewijzing: slecht geheugenbeheer leidt tot overmatige garbagecollection en verminderde prestaties.
- Databaseoverheads: inefficiënte query's en overmatige databaseaanroepen verminderen de prestaties.
In deze casestudy worden visual Studio-profileringshulpprogramma's gebruikt om deze problemen vast te stellen en op te lossen, zodat de toepassing efficiënter en rendabeler wordt.
Uitdaging
Het oplossen van deze prestatieproblemen omvat verschillende uitdagingen:
- Diagnose van knelpunten: het identificeren van hoofdoorzaken van hoge CPU-, geheugen- of databaseoverheads vereist effectief gebruik van profileringshulpprogramma's en een juiste interpretatie van resultaten.
- Kennis- en resourcebeperkingen: profilering en optimalisatie vereisen specifieke vaardigheden en ervaring, die mogelijk niet altijd beschikbaar zijn.
Een strategische aanpak waarbij profileringshulpprogramma's, technische kennis en zorgvuldige tests worden gecombineerd, is essentieel om deze uitdagingen te overwinnen.
Strategie
Hier volgt een algemeen overzicht van de aanpak in deze casestudy:
- Begin met een tracering voor CPU-gebruik met behulp van het hulpprogramma CPU-gebruik van Visual Studio. Het hulpprogramma CPU-gebruik van Visual Studio is een goed uitgangspunt voor prestatieonderzoeken.
- Verzamel extra traceringen voor geheugen- en databaseanalyse:
- Gebruik het hulpprogramma .NET-objecttoewijzing voor geheugeninzichten.
- Gebruik het hulpprogramma Database om SQL-query's en tijdsinstellingen te onderzoeken.
Voor het verzamelen van gegevens zijn de volgende taken vereist:
- Stel de app in op Release-build.
- Selecteer het hulpprogramma CPU-gebruik in Performance Profiler (Alt+F2).
- Start de app in de Prestatieprofiler en verzamel traceergegevens.
Gebieden met hoog CPU-gebruik controleren
Na het verzamelen van een trace met het hulpprogramma CPU-gebruik en het laden ervan in Visual Studio, controleren we eerst de .diagsession rapportpagina met samengevatte gegevens. Gebruik de koppeling Open details in het rapport.
In de detailweergave van het rapport, open de weergave Oproepstructuur. Het codepad met het hoogste CPU-gebruik in de app wordt het hot pathgenoemd. Het pictogram van het hot path-vlam (
) kan helpen om snel prestatieproblemen te identificeren die mogelijk kunnen worden verbeterd.
In de weergave Oproepstructuur ziet u een hoog CPU-gebruik voor de methode GetBlogTitleX in de app, met een aandeel van ongeveer 60% van het CPU-gebruik van de app. De zelf-CPU- waarde voor GetBlogTitleX is echter laag, slechts ongeveer .10%. In tegenstelling tot de totale CPU , sluit de zelf-CPU-waarde tijd uit die in andere functies is besteed, dus we weten dat we dieper in de oproepstructuur moeten zoeken naar het echte knelpunt.
GetBlogTitleX maakt externe aanroepen naar twee LINQ-DLL's, die de meeste CPU-tijd gebruiken, zoals wordt aangetoond door de zeer hoge self-CPU- waarden. Dit is de eerste aanwijzing dat een LINQ-query mogelijk een gebied is om te optimaliseren.
Als u een gevisualiseerde oproepstructuur en een andere weergave van de gegevens wilt krijgen, opent u de Flame Graph weergave. (Of klik met de rechtermuisknop op GetBlogTitleX en kies weergave in Flame Graph.) Hier ziet het er opnieuw uit dat de GetBlogTitleX methode verantwoordelijk is voor een groot deel van het CPU-gebruik van de app (geel). Externe aanroepen naar de LINQ-DLL's worden weergegeven onder het vak GetBlogTitleX en ze gebruiken alle CPU-tijd voor de methode.
Aanvullende gegevens verzamelen
Vaak kunnen andere hulpprogramma's aanvullende informatie bieden om de analyse te helpen en het probleem te isoleren. In deze casestudy gaan we als volgt te werk:
- Bekijk eerst het geheugengebruik. Er kan een correlatie zijn tussen een hoog CPU-gebruik en een hoog geheugengebruik, zodat het handig kan zijn om beide te bekijken om het probleem te isoleren.
- Omdat we de LINQ-DLL's hebben geïdentificeerd, kijken we ook naar het hulpprogramma Database.
Het geheugengebruik controleren
Om te zien wat er met de app gebeurt in termen van geheugengebruik, verzamelen we een tracering met behulp van het hulpprogramma .NET-objecttoewijzing (voor C++kunt u in plaats daarvan het hulpprogramma Geheugengebruik gebruiken). De oproepstructuur weergave in de geheugentracering toont het hot path en helpt ons bij het identificeren van een gebied met een hoog geheugengebruik. Geen verrassing op dit moment, de GetBlogTitleX methode lijkt veel objecten te genereren! Meer dan 900.000 objecttoewijzingen, om precies te zijn.
De meeste gemaakte objecten zijn tekenreeksen, objectmatrices en Int32s. We kunnen mogelijk zien hoe deze typen worden gegenereerd door de broncode te onderzoeken.
Controleer de query in het hulpprogramma Database
In de Performance Profiler selecteren we het hulpprogramma Database in plaats van CPU-gebruik (of selecteer beide). Wanneer we een trace hebben verzameld, opent u het tabblad Queries op de diagnostische pagina. Op het tabblad Query's voor de databasetracering ziet u de eerste rij met de langste query, 2446 ms. In de kolom Records ziet u hoeveel records de query leest. U kunt deze informatie gebruiken voor latere vergelijking.
Door de SELECT-instructie te onderzoeken die is gegenereerd door LINQ in de kolom Query, identificeren we de eerste rij als de query die is gekoppeld aan de GetBlogTitleX methode. Als u de volledige querytekenreeks wilt weergeven, vouwt u de kolombreedte uit. De volledige querytekenreeks is:
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"
U ziet dat de app hier veel kolomwaarden opzoekt, misschien meer dan we nodig hebben. Laten we eens kijken naar de broncode.
Code optimaliseren
Het is tijd om de GetBlogTitleX broncode te bekijken. Klik in het hulpprogramma Database met de rechtermuisknop op de query en kies Ga naar bronbestand. In de broncode voor GetBlogTitleXvinden we de volgende code die LINQ gebruikt om de database te lezen.
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}");
}
}
}
Deze code maakt gebruik van foreach lussen om in de database te zoeken naar blogs met 'Fred Smith' als auteur. U kunt zien dat er veel objecten worden gegenereerd in het geheugen: een nieuwe objectmatrix voor elke blog in de database, gekoppelde tekenreeksen voor elke URL en waarden voor eigenschappen in de berichten, zoals blog-id.
We doen wat onderzoek en vinden enkele algemene aanbevelingen voor het optimaliseren van LINQ-query's. We kunnen ook tijd besparen en Copilot het onderzoek voor ons laten doen.
Als we Copilot gebruiken, selecteren we Vraag Copilot in het contextmenu en typen we de volgende vraag:
Can you make the LINQ query in this method faster?
Aanbeveling
U kunt slash-opdrachten zoals /optimize gebruiken om goede vragen voor Copilot te vormen.
In dit voorbeeld geeft Copilot de volgende voorgestelde codewijzigingen, samen met een uitleg.
public void GetBlogTitleX()
{
var posts = db.Posts
.Where(post => post.Author == "Fred Smith")
.Select(post => post.Title)
.ToList();
foreach (var postTitle in posts)
{
Console.WriteLine($"Post: {postTitle}");
}
}
Deze code bevat verschillende wijzigingen om de query te optimaliseren:
- De
Where-clausule toegevoegd en een van deforeach-lussen verwijderd. - Projecteerde alleen de eigenschap Titel in de instructie
Select. Dit is alles wat we in dit voorbeeld nodig hebben.
Vervolgens testen we opnieuw met behulp van de profileringshulpprogramma's.
Resultaten
Na het bijwerken van de code voeren we het hulpprogramma CPU-gebruik opnieuw uit om een tracering te verzamelen. De oproepstructuur-weergave laat zien dat GetBlogTitleX slechts 1754 ms draait, waarbij 37% van het totale CPU-gebruik van de app wordt gebruikt, een aanzienlijke verbetering ten opzichte van 59%.
Schakel over naar de Flame Graph weergave om een andere visualisatie weer te geven met de verbetering. In deze weergave gebruikt GetBlogTitleX ook een kleiner deel van de CPU.
Controleer de resultaten in de databasetooltracering en slechts twee records worden gelezen met behulp van deze query, in plaats van 100.000! De query is ook veel vereenvoudigd en elimineert de onnodige LEFT JOIN die eerder is gegenereerd.
Vervolgens controleren we de resultaten opnieuw in het hulpprogramma .NET-objecttoewijzing en zien we dat GetBlogTitleX alleen verantwoordelijk is voor 56.000 objecttoewijzingen, bijna een vermindering van 95% van 900.000!
Itereren
Mogelijk zijn er meerdere optimalisaties nodig en kunnen we doorgaan met codewijzigingen om te zien welke wijzigingen de prestaties verbeteren en de rekenkosten verlagen.
Volgende stappen
De volgende artikelen en blogposts bieden meer informatie om u te helpen de Visual Studio-prestatiehulpprogramma's effectief te gebruiken.
- Case-study: Een prestatieprobleem isoleren
- Case Study: Dubbele Prestatie in minder dan 30 minuten
- Visual Studio-prestaties verbeteren met het nieuwe instrumentatieprogramma