Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
A otimização do código reduz o tempo e os custos de computação. Este estudo de caso demonstra como usar as ferramentas de criação de perfil do Visual Studio para identificar e corrigir problemas de desempenho em um aplicativo .NET de exemplo. Se quiser comparar as ferramentas de criação de perfil, consulte Qual ferramenta devo escolher?
Este guia abrange:
- Como usar ferramentas de criação de perfil do Visual Studio para analisar e melhorar o desempenho.
- Estratégias práticas para otimizar o uso da CPU, alocação de memória e interações com o banco de dados.
Aplique estas técnicas para tornar as suas próprias aplicações mais eficientes.
Estudo de caso de otimização
O aplicativo .NET de exemplo executa consultas em um banco de dados SQLite de blogs e postagens usando o Entity Framework. Ele executa muitas consultas, simulando um cenário de recuperação de dados do mundo real. O aplicativo é baseado no exemplo de introdução do Entity Framework, mas usa um conjunto de dados maior.
Os principais problemas de desempenho incluem:
- Alto uso da CPU: Cálculos ineficientes ou tarefas de processamento aumentam o consumo e os custos da CPU.
- Alocação de memória ineficiente: O gerenciamento de memória deficiente leva à coleta excessiva de lixo e ao desempenho reduzido.
- Despesas gerais do banco de dados: consultas ineficientes e chamadas excessivas ao banco de dados degradam o desempenho.
Este estudo de caso usa ferramentas de criação de perfil do Visual Studio para identificar e resolver esses problemas, com o objetivo de tornar o aplicativo mais eficiente e econômico.
Desafio
A correção desses problemas de desempenho envolve vários desafios:
- Diagnóstico de gargalos: Identificar as causas profundas de altas sobrecargas de CPU, memória ou base de dados requer o uso eficaz de ferramentas de análise de desempenho e interpretação correta dos 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 definição de perfis, conhecimento técnico e testes cuidadosos é essencial para superar esses desafios.
Estratégia
Aqui está uma visão de alto nível da abordagem neste estudo de caso:
- Comece com um rastreamento de uso da CPU usando a ferramenta de uso da CPU do Visual Studio. A ferramenta de uso da CPU do Visual Studio é um bom ponto de partida para investigações de desempenho.
- Colete rastreamentos adicionais para análise de memória e banco de dados:
- Use a ferramenta de alocação de objetos .NET para informações sobre memória.
- Utilize a ferramenta de base de dados para examinar consultas SQL e tempos.
A recolha de dados requer as seguintes tarefas:
- Defina o aplicativo como Release build.
- Selecione a ferramenta Uso da CPU no Performance Profiler (Alt+F2).
- No Performance Profiler, inicie a aplicação e recolha um traço.
Inspecione áreas de alto uso da CPU
Depois de coletar um rastreamento com a ferramenta Uso da CPU e carregá-lo no Visual Studio, primeiro verificamos o inicial .diagsession página de relatório que mostra dados resumidos. Utilize o link Abrir detalhes no relatório.
Na vista dos detalhes do relatório, abra a vista Árvore de Chamadas. O caminho de código com maior uso de CPU no aplicativo é chamado de hot path. O ícone de chama de caminho quente (
) pode ajudar a identificar rapidamente problemas de desempenho que podem ser melhorados.
Na visualização da Árvore de Chamadas do, pode ver a grande utilização da CPU pelo método GetBlogTitleX no aplicativo, correspondendo a cerca de 60% do uso total da CPU do aplicativo. No entanto, o valor Self CPU para GetBlogTitleX é baixo, apenas cerca de .10%. Ao contrário, Total CPU, o valor Self CPU exclui o tempo gasto em outras funções, por isso devemos procurar mais abaixo na árvore de chamadas para encontrar o real gargalo.
GetBlogTitleX realiza chamadas externas para duas DLLs LINQ, que estão a utilizar a maior parte do tempo da CPU, como é evidenciado pelos valores muito altos de Self CPU. Esta é a primeira pista de que uma consulta LINQ pode ser uma área a ser otimizada.
Para obter uma árvore de chamadas visualizada e uma exibição diferente dos dados, abra a vista Flame Graph. (Ou, clique com o botão direito do mouse em GetBlogTitleX e escolha Exibir no Flame Graph.) Aqui, novamente, parece que o método GetBlogTitleX é responsável por grande parte do uso da CPU do aplicativo (mostrado em amarelo). Chamadas externas para as DLLs LINQ são exibidas abaixo da caixa GetBlogTitleX e utilizam todo o tempo de CPU do método.
Reunir dados adicionais
Muitas vezes, outras ferramentas podem fornecer informações adicionais para ajudar na análise e isolar o problema. Neste estudo de caso, adotamos a seguinte abordagem:
- Primeiro, observe o uso da memória. Pode haver uma correlação entre alto uso de CPU e alto uso de memória, então pode ser útil examinar ambos para isolar o problema.
- Como identificamos as DLLs LINQ, também examinaremos a ferramenta Banco de dados.
Verificar o uso da memória
Para ver o que se passa com a aplicação em termos de utilização de memória, recolhemos um rasto usando a ferramenta .NET Object Allocation (para C++, pode usar a ferramenta Utilização de Memória). A visualização da Árvore de Chamadas no rastreamento de memória mostra o caminho crítico e nos ajuda a identificar uma área de alto uso de memória. Não é surpresa neste momento, o método GetBlogTitleX parece estar gerando muitos objetos! Mais de 900.000 alocações de objetos, na verdade.
A maioria dos objetos criados são cadeias de caracteres, matrizes de objetos e Int32s. Podemos ver como esses tipos são gerados examinando o código-fonte.
Verifique a consulta na ferramenta Banco de dados
No Performance Profiler, selecionamos a ferramenta Banco de dados em vez de Uso da CPU (ou selecione ambos). Quando tivermos recolhido um rasto, abra a guia Consultas na página de diagnóstico. Na guia Consultas para o rastreamento de banco de dados, você pode ver que a primeira linha mostra a consulta mais longa, 2446 ms. A coluna Registos mostra quantos registos a consulta lê. Você pode usar essas informações para comparação posterior.
Ao examinar a instrução SELECT gerada pelo LINQ na coluna Query, identificamos a primeira linha como a consulta associada ao método GetBlogTitleX. Para exibir a cadeia de caracteres de consulta completa, expanda a largura da coluna. A cadeia de caracteres de consulta completa é:
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"
Observe que o aplicativo está recuperando muitos valores de coluna aqui, talvez mais do que precisamos. Vejamos o código-fonte.
Otimizar código
É hora de dar uma olhada no código-fonte GetBlogTitleX. Na ferramenta Banco de dados, clique com o botão direito do mouse na consulta e escolha Ir para o arquivo de origem. No código-fonte do GetBlogTitleX, encontramos o seguinte código que usa o LINQ para ler o banco de dados.
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}");
}
}
}
Este código usa foreach loops para pesquisar no banco de dados por quaisquer blogs com "Fred Smith" como autor. Olhando para ele, você pode ver que muitos objetos estão sendo gerados na memória: uma nova matriz de objetos para cada blog no banco de dados, cadeias de caracteres associadas para cada URL e valores para propriedades contidas nas postagens, como ID de blog.
Fazemos uma pequena pesquisa e encontramos algumas recomendações comuns sobre como otimizar as consultas LINQ. Alternativamente, podemos economizar tempo e deixar Copilot fazer a pesquisa por nós.
Se estivermos usando o Copilot, selecionamos Ask Copilot no menu de contexto e digitamos a seguinte pergunta:
Can you make the LINQ query in this method faster?
Dica
Você pode usar comandos de barra como /otimize para ajudar a formar boas perguntas para o Copilot.
Neste exemplo, o Copilot fornece as seguintes alterações de código sugeridas, juntamente com uma explicação.
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}");
}
}
Este código inclui várias alterações para ajudar a otimizar a consulta:
- Foi adicionada a cláusula
Wheree eliminado um dos ciclosforeach. - Projetado apenas a propriedade Title na instrução
Select, que é tudo o que precisamos neste exemplo.
Em seguida, testamos novamente usando as ferramentas de criação de perfil.
Resultados obtidos
Depois de atualizar o código, executamos novamente a ferramenta de Utilização da CPU para coletar um registo de execução. A visualização Call Tree mostra que GetBlogTitleX está executando apenas 1754 ms, usando 37% do total de CPU do aplicativo, uma melhoria significativa de 59%.
Alterne para a vista Flame Graph para ver outra visualização que mostra a melhoria. Nessa exibição, GetBlogTitleX também usa uma parte menor da CPU.
Verifique os resultados no rastreamento da ferramenta Banco de dados e apenas dois registros são lidos usando essa consulta, em vez de 100.000! Além disso, a consulta é muito simplificada e elimina o LEFT JOIN desnecessário que foi gerado anteriormente.
Em seguida, verificamos novamente os resultados na ferramenta de alocação de objetos .NET e vemos que GetBlogTitleX é responsável apenas por 56.000 alocações de objetos, uma redução de quase 95% de 900.000!
Iterar
Várias otimizações podem ser necessárias e podemos continuar a iterar com alterações de código para ver quais alterações melhoram o desempenho e ajudam a reduzir o custo de computação.
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.
- Estudo de caso: isolar um problema de desempenho
- Estudo de caso: Desempenho duplo em menos de 30 minutos
- Melhorar o desempenho do Visual Studio com a nova ferramenta de instrumentação