Partilhar via


Estudo de caso: isolar um problema de desempenho (C#, Visual Basic, F#)

Este estudo de caso demonstra como usar as ferramentas de criação de perfil do Visual Studio para identificar e resolver problemas de desempenho em um aplicativo de ASP.NET de exemplo. Para obter uma comparação das ferramentas de criação de perfil, consulte Qual ferramenta devo escolher?

Irá aprender:

  • Como usar ferramentas de criação de perfil do Visual Studio para analisar o desempenho do aplicativo.
  • Como interpretar os dados de análise de desempenho para encontrar gargalos.
  • Estratégias práticas para otimizar o código usando contadores .NET, contagens de chamadas e dados de temporização.

Aplique estas técnicas para melhorar as suas próprias aplicações.

Isolar um estudo de caso sobre desempenho

O aplicativo ASP.NET exemplo executa consultas em um banco de dados simulado e é baseado no Exemplo de diagnóstico.

Principais sintomas de desempenho:

  • Baixo uso da CPU: A CPU não é o gargalo.
  • High ThreadPool Thread Count: A contagem de threads aumenta constantemente, indicando o esgotamento do pool de threads.
  • Resposta lenta do aplicativo: O aplicativo responde lentamente devido à falta de threads disponíveis.

Este estudo de caso usa ferramentas de criação de perfil do Visual Studio para identificar e resolver esses problemas, ajudando você a tornar seu código mais rápido e eficiente.

Desafio

A correção desses problemas envolve vários desafios:

  • Diagnóstico de gargalos: o baixo uso da CPU com desempenho lento pode ter várias causas. É essencial a utilização eficaz das ferramentas de definição de perfis e a interpretação dos seus resultados.
  • Restrições de conhecimento e recursos: A criação de perfis e a otimização exigem habilidades e experiência específicas, que nem sempre estão disponíveis.

Uma abordagem estratégica que combine ferramentas de criação de perfis, conhecimento técnico e testes cuidadosos é fundamental para superar esses desafios.

Estratégia

Aqui está uma visão de alto nível da abordagem neste estudo de caso:

  • Comece monitorando as métricas do contador .NET enquanto coleta dados de desempenho. A ferramenta Contadores .NET do Visual Studio é um bom ponto de partida.
  • Para obter informações mais detalhadas, colete rastreamentos com ferramentas de criação de perfil adicionais, como a ferramenta Instrumentação para contagens de chamadas e dados temporais.

A recolha de dados requer as seguintes tarefas:

  • Defina o aplicativo como Release build.
  • Selecione a ferramenta de Contadores .NET no Perfilador de Desempenho (Alt+F2).
  • Inicie a aplicação e capture um registo.

Verificar contadores de desempenho

Durante a execução do aplicativo, observamos os contadores na ferramenta Contadores .NET. Para investigações iniciais, algumas métricas-chave para ficar de olho incluem:

  • CPU Usage. Observe este contador para ver se ocorre um problema de desempenho com alto ou baixo uso da CPU. Isso pode ser uma pista para tipos específicos de problemas de desempenho. Por exemplo:
    • Com o alto uso da CPU, use a ferramenta Uso da CPU para identificar áreas onde podemos otimizar o código. Para obter um tutorial sobre isso, consulte Estudo de caso: Guia para iniciantes para otimizar o código.
    • Com baixo uso de CPU, use a ferramenta Instrumentação para identificar contagens de chamadas e tempo médio de função com base no tempo de relógio de parede. Isso pode ajudar a identificar problemas como contenção ou esgotamento do pool de threads.
  • Allocation Rate. Para um aplicativo Web que atende solicitações, a taxa deve ser bastante estável.
  • GC Heap Size. Veja este contador para verificar se o uso de memória está a crescer continuamente e com potencial para vazamentos. Se parecer alto, use uma das ferramentas de uso de memória.
  • Threadpool Thread Count. Para um aplicativo Web que atende solicitações, observe esse contador para ver se a contagem de threads está se mantendo estável ou aumentando a uma taxa constante.

Aqui está um exemplo mostrando como o CPU Usage é baixo, enquanto o ThreadPool Thread Count é relativamente alto.

Captura de tela dos contadores mostrados na ferramenta Contadores .NET.

Uma contagem de threads cada vez maior com um baixo uso da CPU pode ser um indicador de esgotamento do pool de threads. O pool de threads é forçado a continuar girando novos threads. A saturação do pool de threads ocorre quando o pool não tem threads disponíveis para processar novos itens de trabalho e geralmente resulta em uma resposta lenta dos aplicativos.

Com base no baixo uso da CPU e na contagem relativamente alta de threads, e considerando a teoria de um possível caso de inanição do pool de threads, altere para usar a ferramenta de instrumentação.

Investigue contagens de chamadas e dados de temporização

Vamos dar uma olhada num rastreio da ferramenta de Instrumentação para ver se conseguimos descobrir mais sobre o que está a acontecer com os threads.

Depois de coletar um rastreamento com a ferramenta Instrumentação e carregá-lo no Visual Studio, primeiro verificamos o inicial .diagsession página de relatório que mostra dados resumidos. No rastreamento coletado, usamos o link Abrir detalhes no relatório e, em seguida, selecionamos Gráfico de chama.

Captura de tela do Flame Graph na ferramenta Instrumentação.

A visualização do Flame Graph nos mostra que a função QueryCustomerDB (mostrada em amarelo) é responsável por uma parte significativa do tempo de execução do aplicativo.

Clique com o botão direito do mouse na função QueryCustomerDB e escolha Exibir na árvore de chamadas.

Captura de tela da árvore de chamadas na ferramenta Instrumentação.

O caminho de código com maior uso de CPU no aplicativo é chamado de hot path. O ícone de chama do "hot path" (Captura de tela que mostra o ícone do hot path.) pode ajudar a identificar rapidamente problemas de desempenho que podem ser melhorados.

Na visualização da Árvore de Chamadas do, você pode ver que o caminho ativo inclui a função QueryCustomerDB, que aponta para um possível problema de desempenho.

Em relação ao tempo gasto em outras funções, os valores Self e Avg Self para a função QueryCustomerDB são muito altos. Ao contrário de Total e Total Médio, os valores de Self excluem o tempo gasto em outras funções, portanto, este é um bom lugar para procurar o gargalo de desempenho.

Dica

Se os valores Self fossem relativamente baixos em vez de altos, você provavelmente iria querer ver as consultas reais chamadas pela função QueryCustomerDB.

Clique duas vezes na função QueryCustomerDB para mostrar o código-fonte da função.

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

Fazemos uma pequena pesquisa. Alternativamente, podemos economizar tempo e deixar Copilot fazer a pesquisa por nós.

Se estivermos usando Copilot, selecione Ask Copilot no menu de contexto e digite a seguinte pergunta:

Can you identify a performance issue in the QueryCustomerDB method?

Dica

Você pode usar comandos de barra como /otimize para ajudar a formar boas perguntas para o Copilot.

O Copilot nos diz que esse código está chamando uma API assíncrona sem usar await. Este é o padrão de código de sync-over-async, que é uma causa comum de esgotamento do threadpool e pode bloquear threads.

Para resolver, use aguardar. Neste exemplo, o Copilot dá a seguinte sugestão de código juntamente com a explicação.

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

Se você vir problemas de desempenho relacionados a consultas de banco de dados, poderá usar a ferramenta Banco de Dados para investigar se determinadas chamadas são mais lentas. Esses dados podem indicar uma oportunidade para otimizar consultas. Para obter um tutorial que mostra como usar a ferramenta Banco de dados para investigar um problema de desempenho, consulte Estudo de caso: Guia para iniciantes para otimizar o código. A ferramenta Banco de Dados oferece suporte ao .NET Core com ADO.NET ou Entity Framework Core.

Para obter visualizações no Visual Studio para comportamento de thread individual, pode-se usar a janela Pilhas Paralelas durante a depuração. Esta janela mostra threads individuais, juntamente com informações sobre threads que estão à espera, threads pelas quais estão à espera e deadlocks.

Para obter informações adicionais sobre a exaustão do pool de threads, consulte Deteção da exaustão do pool de threads.

Próximos passos

Os seguintes artigos e postagens de blog fornecem mais informações para ajudá-lo a aprender a usar as ferramentas de desempenho do Visual Studio de forma eficaz.