Dela via


Fallstudie: Isolera ett prestandaproblem (C#, Visual Basic, F#)

Använd profileringsverktygen för att undersöka prestandaproblem och isolera problemområden. I den här fallstudien används ett exempelprogram med prestandaproblem för att visa hur du använder profileringsverktyg för att förbättra effektiviteten. Om du vill jämföra profileringsverktyg kan du läsa Vilket verktyg ska jag välja?

Den här fallstudien beskriver följande ämnen:

  • Så här använder du Visual Studio-profileringsverktyg för att analysera programprestanda.
  • Så här tolkar du de data som tillhandahålls av dessa verktyg för att identifiera prestandaflaskhalsar.
  • Använda praktiska strategier för att optimera kod, med fokus på .NET-räknare, antal samtal och tidsdata.

Följ med och tillämpa dessa tekniker på dina egna program för att göra dem mer effektiva och kostnadseffektiva.

Identifiera ett prestandaproblem i en fallstudie

Exempelprogrammet i den här fallstudien är en ASP.NET app som kör frågor mot en simulerad databas. Exemplet baseras på Diagnostics Sample.

Det primära prestandaproblemet med exempelprogrammet ligger i ineffektiva kodningsmönster. Programmet har en flaskhals för prestanda som avsevärt påverkar dess effektivitet. Problemet omfattar följande symtom:

  • låg CPU-användning: Programmet visar låg CPU-användning, vilket indikerar att processorn inte är flaskhalsen.

  • Högt antal trådar i trådpool: Antalet trådar är relativt högt och stiger stadigt, vilket tyder på resursuttömning i trådpoolen.

  • Långsamt programsvar: Programmet svarar långsamt på grund av bristen på tillgängliga trådar för att bearbeta nya arbetsobjekt.

Fallstudien syftar till att åtgärda dessa problem genom att använda Visual Studios profileringsverktyg för att analysera programmets prestanda. Genom att förstå var och hur programmets prestanda kan förbättras kan utvecklare implementera optimeringar för att göra koden snabbare och effektivare. Det ultimata målet är att förbättra programmets övergripande prestanda, vilket gör det mer effektivt och kostnadseffektivt att köra.

Utmaning

Att åtgärda prestandaproblemen i .NET-exempelprogrammet innebär flera utmaningar. Dessa utmaningar beror på komplexiteten i att diagnostisera flaskhalsar i prestanda. De viktigaste utmaningarna med att åtgärda de problem som beskrivs är följande:

  • Diagnosering av prestandaflaskhalsar: En av de främsta utmaningarna är att exakt identifiera grundorsakerna till prestandaproblemen. Låg CPU-användning i kombination med långsam prestanda kan ha flera bidragande faktorer. Utvecklare måste använda profileringsverktyg effektivt för att diagnostisera dessa problem, vilket kräver viss förståelse för hur dessa verktyg fungerar och hur de tolkar sina utdata.

  • kunskaps- och resursbegränsningar: Teams kan stöta på begränsningar som rör kunskap, expertis och resurser. Profilering och optimering av ett program kräver specifika kunskaper och erfarenheter, och alla team kan inte ha omedelbar åtkomst till dessa resurser.

Att hantera dessa utmaningar kräver en strategisk metod som kombinerar effektiv användning av profileringsverktyg, teknisk kunskap och noggrann planering och testning. Fallstudien syftar till att vägleda utvecklare genom den här processen, tillhandahålla strategier och insikter för att övervinna dessa utmaningar och förbättra programmets prestanda.

Strategi

Här är en översikt över metoden i den här fallstudien:

  • Vi startar undersökningen genom att titta på .NET-räknarmått när vi samlar in prestandadata. Precis som verktyget CPU-användning är Visual Studios .NET-räknare verktyg också en bra utgångspunkt för en prestandaundersökning.
  • För ytterligare insikter som hjälper till att isolera problem eller förbättra prestanda kan du sedan samla in en spårning med hjälp av något av de andra profileringsverktygen. Ta till exempel en titt på antal samtal och tidsdata med hjälp av verktyget Instrumentation.

Datainsamling kräver följande uppgifter:

  • Ställa in appen på en releasebyggnad.
  • Välj verktyget .NET-räknare från Prestandaprofiler (Alt+F2). (Senare steg omfattar instrumenteringsverktyget.)
  • Starta appen från Prestandaprofiler och samla in en spårning.

Kontrollera prestandaräknare

När vi kör appen observerar vi räknarna i .NET Counters-verktyget. För inledande undersökningar är några viktiga mått att hålla ett öga på:

  • CPU Usage. Titta på den här räknaren för att se om ett prestandaproblem uppstår med hög eller låg CPU-användning. Detta kan vara en ledtråd till specifika typer av prestandaproblem. Till exempel:
    • Med hög CPU-användning använder du verktyget CPU-användning för att identifiera områden där vi kanske kan optimera kod. För en handledning om detta, se Fallstudie: Nybörjarguide för att optimera kod.
    • Med låg CPU-användning använder du verktyget Instrumentation för att identifiera antal anrop och genomsnittlig funktionstid baserat på klocktid på väggen. Detta kan hjälpa dig att identifiera problem som konkurrens eller utsvulten trådpool.
  • Allocation Rate. För en webbapp som betjänar begäranden bör priset vara ganska stabilt.
  • GC Heap Size. Titta på den här räknaren för att se om minnesanvändningen ökar kontinuerligt och potentiellt läcker. Om den verkar hög använder du något av verktygen för minnesanvändning.
  • Threadpool Thread Count. För en webbapp som betjänar begäranden kan du titta på den här räknaren för att se om antalet trådar håller stadigt eller ökar i en stadig takt.

Här är ett exempel som visar hur CPU Usage är låg, medan ThreadPool Thread Count är relativt hög.

Skärmbild av räknare som visas i verktyget .NET-räknare.

Ett stadigt ökande antal trådar med låg CPU-användning kan vara en indikator på utsvulten trådpool. Trådpoolen tvingas fortsätta snurra nya trådar. Utsvulten trådpool uppstår när poolen inte har några tillgängliga trådar för att bearbeta nya arbetsobjekt och det ofta gör att program svarar långsamt.

Baserat på den låga CPU-användningen och det relativt höga trådantalet, samt utifrån teorin om ett möjligt fall av trådpoolssvält, växlar du till att använda instrumentationsverktyget.

Undersöka antal samtal och tidsdata

Låt oss ta en titt på en spårning från instrumenteringsverktyget för att se om vi kan försöka ta reda på mer om vad som händer med trådarna.

När du har samlat in en spårning med verktyget Instrumentation och läst in den i Visual Studio kontrollerar vi först rapportsidan .diagsession som visar sammanfattade data. I det insamlade spåret använder vi länken Öppna detaljer i rapporten och väljer sedan Flame Graph.

Skärmbild av Flame Graph i instrumenteringsverktyget.

Flame Graph-visualiseringen visar oss att funktionen QueryCustomerDB (visas i gult) ansvarar för en betydande del av appens körningstid.

Högerklicka på funktionen QueryCustomerDB och välj Visa i anropshierarkin.

Skärmbild av samtalsträdet i instrumenteringsverktyget.

Kodsökvägen med högsta CPU-användning i appen kallas frekvent sökväg. Flamikonen för frekvent sökväg (Skärmbild som visar ikonen För frekvent sökväg.) kan hjälpa dig att snabbt identifiera prestandaproblem som kan förbättras.

I vyn Samtalsträd kan du se att den heta sökvägen innehåller funktionen QueryCustomerDB, vilket pekar på ett potentiellt prestandaproblem.

I förhållande till tiden i andra funktioner är värdena Self och Avg Self för funktionen QueryCustomerDB mycket höga. Till skillnad från Total och Avg Total, utesluter Self-värden tid som spenderats i andra funktioner, så det här är ett bra ställe att leta efter flaskhalsen för prestanda.

Tips

Om värdena för Self var relativt låga i stället för höga, skulle du förmodligen vilja titta på de faktiska frågor som anropas av funktionen QueryCustomerDB.

Dubbelklicka på funktionen QueryCustomerDB för att visa källkoden för funktionen.

public ActionResult<string> QueryCustomerDB()
{
    Customer c = QueryCustomerFromDbAsync("Dana").Result;
    return "success:taskwait";
}

Vi gör lite efterforskningar. Alternativt kan vi spara tid och låta Copilot göra forskningen åt oss.

Om vi använder Copilotväljer du Fråga Copilot på snabbmenyn och skriver följande fråga:

Can you identify a performance issue in the QueryCustomerDB method?

Tips

Du kan använda snedstreckskommandon som /optimize för att skapa bra frågor för Copilot.

Copilot meddelar oss att den här koden anropar ett asynkront API utan att använda await. Det här är kodmönster för synkronisering över asynkronisering, vilket är en vanlig orsak till utsvulten trådpool och kan blockera trådar.

Lös problemet genom att använda await. I det här exemplet ger Copilot följande kodförslag tillsammans med förklaringen.

public async Task<ActionResult<string>> QueryCustomerDB()
{
    Customer c = await QueryCustomerFromDbAsync("Dana");
    return "success:taskwait";
}

Om du ser prestandaproblem som rör databasfrågor kan du använda verktyget Database för att undersöka om vissa anrop är långsammare. Dessa data kan tyda på en möjlighet att optimera frågor. En självstudiekurs som visar hur du använder databasverktyget för att undersöka ett prestandaproblem finns i Fallstudie: Nybörjarguide för att optimera kod. Databasverktyget stöder .NET Core med antingen ADO.NET eller Entity Framework Core.

Om du vill hämta visualiseringar i Visual Studio för enskilda trådbeteenden kan du använda fönstret Parallella staplar under felsökning. Det här fönstret visar enskilda trådar tillsammans med information om trådar som väntar, trådarna de väntar på och dödlägen.

Mer information om utsvulten trådpool finns i Detecting threadpool starvation.

Nästa steg

Följande artiklar och blogginlägg innehåller mer information som hjälper dig att lära dig att använda Visual Studio-prestandaverktygen effektivt.