Guide du débutant pour optimiser le code et réduire les coûts de calcul (C#, Visual Basic, C++, F#)
Réduire le temps de calcul signifie réduire les coûts, donc l’optimisation de votre code peut faire des économies. Dans cet article, nous montrons comment vous pouvez utiliser différents outils de profilage pour vous aider à accomplir cette tâche.
Au lieu de fournir des instructions pas à pas, notre intention est de vous montrer comment utiliser efficacement les outils de profilage et comment interpréter les données. L’outil Utilisation du processeur peut vous aider à capturer et à visualiser où les ressources de calcul sont utilisées dans votre application. Les affichages Utilisation de l’UC tels que l’arborescence des appels et le graphique en flamme fournissent une visualisation graphique agréable de l’endroit où le temps est passé dans votre application. En outre, les insights automatiques peuvent afficher des optimisations précises qui peuvent avoir un impact important. D’autres outils de profilage peuvent également vous aider à isoler les problèmes. Pour comparer les outils, consultez Quel outil choisir ?
Démarrer une investigation
- Commencez votre enquête en effectuant une trace de l’utilisation de l’UC. L’outil Utilisation du processeur est souvent utile pour commencer les investigations de performances et pour optimiser le code afin de réduire les coûts.
- Ensuite, si vous souhaitez obtenir des informations supplémentaires pour isoler les problèmes ou améliorer le niveau de performance, envisagez de collecter une trace à l’aide de l’un des autres outils de profilage. Par exemple :
- Examinez l’utilisation de la mémoire. Pour .NET, essayez d’abord l’outil Allocation d’objets .NET. Pour .NET ou C++, vous pouvez consulter l’outil Utilisation de la mémoire.
- Si votre application utilise l’E/S de fichier, utilisez l’outil D/S fichier.
- Si vous utilisez ADO.NET ou Entity Framework, vous pouvez essayer l’outil Base de données pour examiner les requêtes SQL, l’heure précise des requêtes, etc.
Exemple de collections de données
Les exemples de captures d’écran présentés dans cet article sont basés sur une application .NET qui exécute des requêtes sur une base de données de blogs et de billets de blog associés. Vous allez d’abord examiner une trace d’utilisation du processeur pour rechercher les opportunités d’optimisation du code et de réduction des coûts de calcul. Après avoir une idée générale de ce qui se passe, vous examinerez également les traces d’autres outils de profilage pour vous aider à isoler les problèmes.
La collecte de données nécessite les étapes suivantes (non affichées ici) :
- Définir votre application sur une build de mise en production
- Sélectionnez l’outil Utilisation du processeur dans le Profileur de performances (Alt+F2). (Les étapes ultérieures impliquent quelques-uns des autres outils.)
- À partir du Profileur de performances, démarrez l’application et collectez une trace.
Inspecter les zones d’utilisation élevée du processeur
Commencez par collecter une trace avec l’outil Utilisation du processeur. Lorsque les données de diagnostic se chargent, tout d’abord vérifiez la page de rapport .diagsession initiale qui affiche Insights supérieurs et le chemin chaud. Le chemin chaud affiche le chemin du code avec l’utilisation la plus élevée du processeur dans votre application. Ces sections peuvent fournir des conseils pour vous aider à identifier rapidement les problèmes de performances que vous pouvez améliorer.
Vous pouvez également afficher le chemin chaud dans l’affichage Arborescence des appels. Pour ouvrir cet affichage, utilisez le lien Ouvrir les détails dans le rapport, puis sélectionnez Arborescence des appels.
Dans cet affichage, vous voyez à nouveau le chemin chaud, qui montre une utilisation élevée du processeur pour la GetBlogTitleX
méthode dans l’application, en utilisant environ 60 % de l’utilisation du processeur de l’application. Toutefois, la valeur de l’auto-processeur pour GetBlogTitleX
est faible, seulement environ .10%. Contrairement au processeur total, la valeur de l’auto-processeur exclut le temps passé dans d’autres fonctions. Nous savons qu’il faut regarder plus loin dans l’Arborescence des appels pour trouver le goulot d’étranglement réel.
GetBlogTitleX
effectue des appels externes à deux DLL LINQ, qui utilisent la plupart du temps processeur, comme le montrent les valeurs très élevées de l’auto-processeur. Il s’agit du premier indice que vous pouvez rechercher une requête LINQ en tant que zone à optimiser.
Pour obtenir une arborescence d’appels visualisées et un autre affichage des données, basculez vers la vue Graphique de type flamme (sélectionnez dans la même liste que l’arborescence des appels). Là encore, il semble que la méthode GetBlogTitleX
soit responsable d’une grande partie de l’utilisation du processeur de l’application (illustré en jaune). Les appels externes aux DLL LINQ s’affichent sous la boîte GetBlogTitleX
et ils utilisent tout le temps processeur pour la méthode.
Collecter des données supplémentaires
Souvent, d’autres outils peuvent fournir des informations supplémentaires pour contribuer à l’analyse et isoler le problème. Pour cet exemple, nous adoptons l’approche suivante :
- Tout d’abord, nous allons examiner l’utilisation de la mémoire. Il peut y avoir une corrélation entre une utilisation élevée de l’UC et une utilisation élevée de la mémoire. Il peut donc être utile d’examiner les deux pour isoler le problème.
- Comme nous avons identifié les DLL LINQ, nous allons également examiner l’outil Base de données.
Vérifier l’utilisation de la mémoire
Pour voir ce qui se passe avec l’application en termes d’utilisation de la mémoire, collectez une trace à l’aide de l’outil d’allocation d’objets .NET. (Pour C++, utilisez l’outil d’utilisation de la mémoire). L’affichage Arborescence des appels dans la trace de mémoire affiche le chemin chaud et vous aide à identifier une zone d’utilisation élevée de la mémoire. Pas de surprise à ce stade, la méthode GetBlogTitleX
semble générer beaucoup d’objets ! Plus de 900 000 allocations d’objets, en fait.
La plupart des objets créés sont des chaînes, des tableaux d’objets et des Int32. Vous pourrez peut-être voir comment ces types sont générés en examinant le code source.
Vérifier la requête dans l’outil Base de données
Vous pouvez sélectionner plusieurs fois l’outil Base de données ainsi que l’utilisation de l’UC. Une fois que vous avez collecté une trace, sélectionnez l’onglet Requêtes dans la page diagnostics. Dans l’onglet Requêtes de la trace de base de données, vous pouvez voir que la première ligne affiche la requête la plus longue, 2 446 ms. La colonne Enregistrements indique le nombre d’enregistrements que la requête lit. Nous pouvons utiliser ces informations pour une comparaison ultérieure.
En examinant l’instruction SELECT
générée par LINQ dans la colonne Requête, vous identifiez la première ligne comme la requête associée à la méthode GetBlogTitleX
. Pour afficher la chaîne de requête complète, développez la largeur de colonne si nécessaire. La chaîne de requête complète est la suivante :
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"
Notez que vous récupérez ici beaucoup de valeurs de colonne, peut-être plus que nécessaire. Examinons le code source.
Optimiser le code
Il est temps d’examiner le code source GetBlogTitleX
. Dans l’outil Base de données, cliquez avec le bouton droit sur la requête et choisissez Accéder au fichier source. Dans le code source de GetBlogTitleX
, nous trouvons le code suivant qui utilise LINQ pour lire la base de données.
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}");
}
}
}
Ce code utilise des boucles foreach
pour rechercher la base de données tous les blogs avec « Fred Smith » comme auteur. En l’examinant, vous pouvez voir que de nombreux objets sont générés en mémoire : un nouveau tableau d’objets pour chaque blog de la base de données, des chaînes associées pour chaque URL et des valeurs pour les propriétés contenues dans les billets, comme l’ID de blog.
Vous effectuez quelques recherches et trouvez des suggestions courantes sur la façon d’optimiser les requêtes LINQ et de créer ce code.
foreach (var x in db.Posts.Where(p => p.Author.Contains("Fred Smith")).Select(b => b.Title).ToList())
{
Console.WriteLine("Post: " + x);
}
Dans ce code, vous avez apporté plusieurs modifications pour optimiser la requête :
- Vous avez ajouté la clause
Where
et supprimé l’une des bouclesforeach
. - Vous avez projeté uniquement la propriété Titre dans l’instruction
Select
, ce qui est tout ce dont vous avez besoin dans cet exemple.
Ensuite, retestez à l’aide des outils de profilage.
Vérification des résultats
Après avoir mis à jour le code, réexécutez l’outil Utilisation du processeur pour collecter une trace. L’affichage Arborescence des appels montre que GetBlogTitleX
ne s’exécute que 1 754 ms, en utilisant 37 % du processeur total de l’application, une amélioration significative par rapport à 59 %.
Basculez vers l’affichage Graphique de type flamme pour afficher une autre visualisation de l’amélioration. Dans cet affichage, GetBlogTitleX
utilise également une plus petite partie du processeur.
Vérifiez les résultats dans la trace de l’outil de base de données et seuls deux enregistrements sont lus à l’aide de cette requête, au lieu de 100 000 ! En outre, la requête est beaucoup simplifiée et élimine la jointure LEFT inutile qui a été générée précédemment.
Ensuite, vérifiez à nouveau les résultats dans l’outil d’allocation d’objets .NET et vérifiez que GetBlogTitleX
n’est responsable que de 56 000 allocations d’objets, soit une réduction de près de 95 % par exemple de 900 000 !
Itérer
Plusieurs optimisations peuvent être nécessaires et vous pouvez continuer à itérer avec les modifications du code pour voir quelles modifications améliorent le niveau de performance et réduisent votre coût de calcul.
Étapes suivantes
Les billets de blog suivants fournissent plus d’informations pour vous aider à apprendre à utiliser efficacement les outils de performances Visual Studio.
- Amélioration des performances de Visual Studio avec le nouvel outil d’instrumentation
- Étude de cas : Doubler les performances en moins de 30 minutes
Contenu connexe
Commentaires
https://aka.ms/ContentUserFeedback.
Bientôt disponible : Tout au long de 2024, nous allons supprimer progressivement GitHub Issues comme mécanisme de commentaires pour le contenu et le remplacer par un nouveau système de commentaires. Pour plus d’informations, consultezEnvoyer et afficher des commentaires pour