Condividi tramite


Isolare un problema di prestazioni (C#, Visual Basic, F#)

In questo articolo si apprenderà come usare gli strumenti di profilatura per analizzare i problemi di prestazioni e isolare le aree problematiche.

Invece di fornire istruzioni dettagliate, l'intento di seguito è illustrare come usare gli strumenti di profilatura in modo efficace e come interpretare i dati. Come lo strumento Utilizzo CPU, lo strumento contatori .NET è anche un buon punto di partenza per un'analisi delle prestazioni. Dopo aver identificato dati interessanti, è possibile usare altri strumenti di profilatura per analizzare in modo più approfondito. Per confrontare gli strumenti, vedere Quale strumento scegliere?

Informazioni sull'app di esempio

Gli screenshot in questo articolo si basano su un'app ASP.NET che esegue query su un database simulato. L'esempio è basato sull'esempio di diagnostica.

Avviare un'indagine

  • Avviare l'indagine osservando le metriche dei contatori .NET durante la raccolta dei dati sulle prestazioni.
  • Per altre informazioni dettagliate per isolare i problemi, prendere in considerazione la raccolta di una traccia usando uno degli altri strumenti di profilatura, ad esempio lo strumento Utilizzo CPU, lo strumento Strumentazione e altri.

La raccolta dei dati richiede i passaggi seguenti (non illustrati in questo articolo):

  • Impostare l'app su una build di rilascio.
  • Selezionare lo strumento Contatori .NET dal Profiler prestazioni (ALT+F2). I passaggi successivi coinvolgono lo strumento di strumentazione.
  • Dal Profiler prestazioni avviare l'app.

Controllare i contatori delle prestazioni

Durante l'esecuzione dell'app, visualizzare i contatori nello strumento Contatori .NET. Per le indagini iniziali, alcune metriche chiave da tenere d'occhio includono:

  • CPU Usage. Guardare questo contatore per verificare se si verifica un problema di prestazioni con un utilizzo elevato o basso della CPU. Questo può essere un indizio di tipi specifici di problemi di prestazioni. Ad esempio:
    • Con un utilizzo elevato della CPU, usare lo strumento Utilizzo CPU per identificare le aree in cui è possibile ottimizzare il codice. Per un'esercitazione su questo argomento, vedere la guida per principianti all'ottimizzazione del codice.
    • Con un utilizzo ridotto della CPU, usare lo strumento Strumentazione per identificare i conteggi delle chiamate e il tempo medio della funzione in base all'ora di clock del muro. Ciò può aiutare a identificare problemi quali contesa o fame del pool di thread.
  • Allocation Rate. Per un'app Web che gestisce le richieste, la frequenza deve essere abbastanza costante.
  • GC Heap Size. Guardare questo contatore per verificare se l'utilizzo della memoria è in continua crescita e potenzialmente in perdita. Se sembra elevato, è possibile usare uno degli strumenti di utilizzo della memoria.
  • Threadpool Thread Count. Per un'app Web che gestisce le richieste, controllare questo contatore per verificare se il conteggio dei thread è costante o in aumento a un tasso costante.

Di seguito è riportato un esempio che mostra come è CPU Usage basso, mentre è ThreadPool Thread Count relativamente alto.

Screenshot dei contatori visualizzati nello strumento Contatori .NET.

Un numero di thread in costante aumento con un utilizzo ridotto della CPU può essere un indicatore della fame del pool di thread. Il pool di thread è costretto a continuare a ruotare nuovi thread. La fame del pool di thread si verifica quando il pool non dispone di thread disponibili per elaborare nuovi elementi di lavoro e spesso fa sì che le applicazioni rispondano lentamente.

In base al basso utilizzo della CPU e al numero di thread relativamente elevato e all'uso della teoria di un possibile caso di fame del pool di thread, passare all'uso dello strumento strumentazione.

Analizzare i conteggi delle chiamate e i dati di intervallo

Verrà ora esaminata una traccia dello strumento Strumentazione per verificare se è possibile provare a scoprire di più su cosa sta accadendo con i thread.

Quando i dati di diagnostica vengono caricati, controllare prima di tutto la pagina iniziale del report con estensione diagsession che mostra Le informazioni dettagliate principali e il percorso critico. Nella traccia Strumentazione il percorso critico mostra il percorso del codice con tempi di funzione più lunghi nell'app. Queste sezioni possono fornire suggerimenti utili per identificare rapidamente i problemi di prestazioni che è possibile migliorare.

Nella traccia raccolta usare il collegamento Apri dettagli nel report e quindi selezionare Flame Graph.

Screenshot di Flame Graph nello strumento Strumentazione.

La visualizzazione Flame Graph mostra che la QueryCustomerDB funzione è responsabile di una parte significativa del tempo di esecuzione dell'app.

Fare clic con il pulsante destro del mouse sulla QueryCustomerDB funzione e scegliere Visualizza in Albero delle chiamate.

Screenshot dell'albero delle chiamate nello strumento strumentazione.

Nella visualizzazione Albero delle chiamate si noterà che l'icona Percorso critico (icona di fiamma) include la QueryCustomerDB funzione , che punta a un potenziale problema di prestazioni.

Rispetto al tempo impiegato in altre funzioni, i valori Self e Avg Self per la QueryCustomerDB funzione sono molto elevati. A differenza di Total e Avg Total, i valori Self escludono il tempo impiegato in altre funzioni, quindi questo è un buon posto per cercare il collo di bottiglia delle prestazioni.

Suggerimento

Se i valori Self erano relativamente bassi anziché alti, è probabile che si voglia esaminare le query effettive chiamate dalla QueryCustomerDB funzione.

Fare doppio clic sulla QueryCustomerDB funzione per visualizzare il codice sorgente per la funzione.

public ActionResult<string> QueryCustomerDB()
{

    Task dbTask = QueryCustomerFromDbAsync("Dana");
    return "success:tasksleepwait";
}

Con una piccola ricerca, si scopre che questo codice chiama un'API asincrona senza usare await. Si tratta del modello di codice sincrona over-asincrono , che è una causa comune di starvation del pool di thread e può bloccare i thread.

Per risolvere il problema, usare await.

public async Task<ActionResult<string>> TaskAsyncWait()
{
    Customer c = await PretendQueryCustomerFromDbAsync("Dana");
    return "success:taskasyncwait";
}

Se vengono visualizzati problemi di prestazioni relativi alle query di database, è possibile usare lo strumento Database per verificare se determinate chiamate sono più lente. Questi dati possono indicare un'opportunità per ottimizzare le query. Per un'esercitazione che illustra come usare lo strumento database per analizzare un problema di prestazioni, vedere la guida per principianti all'ottimizzazione del codice. Lo strumento Database supporta .NET Core con ADO.NET o Entity Framework Core.

Per ottenere visualizzazioni in Visual Studio per il comportamento dei singoli thread, è possibile usare la finestra Stack paralleli durante il debug. Questa finestra mostra i singoli thread insieme alle informazioni sui thread in attesa, sui thread in attesa e sui deadlock.

Per altre informazioni sulla fame del pool di thread, vedere Detecting threadpool starvation.For additional information on thread pool starvation, see Detecting threadpool starvation.

Passaggi successivi

Gli articoli e i post di blog seguenti forniscono altre informazioni per imparare a usare in modo efficace gli strumenti per le prestazioni di Visual Studio.