Dela via


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

Den här fallstudien visar hur du använder Visual Studio-profileringsverktyg för att identifiera och lösa prestandaproblem i ett exempel ASP.NET program. En jämförelse av profileringsverktyg finns i Vilket verktyg ska jag välja?

Du får lära dig detta:

  • Så här använder du Visual Studio-profileringsverktyg för att analysera programprestanda.
  • Så här tolkar du profileringsdata för att hitta flaskhalsar.
  • Praktiska strategier för att optimera kod med hjälp av .NET-räknare, antal anrop och tidsdata.

Använd dessa tekniker för att förbättra dina egna program.

Identifiera ett prestandaproblem i en fallstudie

Exempelprogrammet ASP.NET kör frågor mot en simulerad databas och baseras på diagnostikexemplet.

Viktiga prestandasymtom:

  • Låg CPU-användning: Processorn är inte flaskhalsen.
  • Högt antal threadpooltrådar: Antalet trådar ökar stadigt, vilket indikerar utsvulten trådpool.
  • Långsamt programsvar: Appen svarar långsamt på grund av brist på tillgängliga trådar.

Den här fallstudien använder Visual Studio-profileringsverktyg för att hitta och åtgärda dessa problem, vilket hjälper dig att göra koden snabbare och effektivare.

Utmaning

Att åtgärda dessa problem innebär flera utmaningar:

  • Diagnostisera flaskhalsar: Låg CPU-användning med långsamma prestanda kan ha flera orsaker. Effektiv användning av profileringsverktyg och tolkning av deras utdata är viktigt.
  • Kunskaps- och resursbegränsningar: Profilering och optimering kräver specifika kunskaper och erfarenheter, som kanske inte alltid är tillgängliga.

En strategisk metod för att kombinera profileringsverktyg, teknisk kunskap och noggrann testning är nyckeln till att övervinna dessa utmaningar.

Strategi

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

  • Börja med att övervaka .NET-räknarmått när du samlar in prestandadata. Visual Studios .NET Counters-verktyg är en bra utgångspunkt.
  • För djupare insikter samlar du in spårningar med ytterligare profileringsverktyg, till exempel instrumenteringsverktyget för antal anrop och tidsdata.

Datainsamling kräver följande uppgifter:

  • Ställ in appen på släppversion.
  • Välj verktyget .NET Counters i Performance Profiler (Alt+F2).
  • Starta appen 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.