.Net et la performance

.NET.NET CorePerformance
Pierrick Gourlain - 22/03/2019 à 14:45:100 commentaire

.Net et la performance


Vaste sujet que celui de la performance. Un de mes stagiaires a décidé d’écrire en C#, un réseaux de neurones pour de la reconnaissance de visages. Et donc pour calculer son modèle, cela prennait plusieurs heures...Donc à chaque fois qu'il voulait régénérer sont modèle... sa machine était occupée pour un moment. Ainsi à démarré une discussion autour de la performance de son code...


En effet la performance peut être liée au framework lui même (dotnet / dotnet core et ses différentes versions). Pour cela il existe un certain nombre de comparatifs (parmi les plus connus, un comparatif sur le serveur http en .net core)

 

source : https://www.ageofascent.com/2019/02/04/asp-net-core-saturating-10gbe-at-7-million-requests-per-second/


Vous pouvez trouver également les évolutions en terme de performance, par exemple en .Net Core 2.0 et 2.1( blog). Ici on parle d'amélioration de performance netre version d'un même framework. Par ailleurs, si vous êtes en .Net Framework et que vous souhaitez avoir quelques éléments de comparaison avec .Net Core, voir NodeJS, voici un autre blog.


A ce stade en fonction de votre utilisation du Framework, vous avez des éléments de comparaison, pour orienter vos développements et/ou vos choix en fonction de vos contraintes de projet et/ou déploiement.


Pour aller plus loin vous pouvez vous même effectuer des "benchmarks" de vos algorithmes en utilisant benchmarkdotnet, qui peut vous sortir un comparatif de votre algorithme entre .Net,.NetCore,Mono.

 

source : https://benchmarkdotnet.org



Il existe d'autres aspects de la performance, liés à l’écriture de votre code, et ici il y a beaucoup d'axes d'amélioration (Async/await, mémoire, méthodes, validations des arguments, debug/release, Fwk en Preview,...). Regardons de plus près.


Async/Await


Depuis quelques temps async/await sont utilisés partout , et pour bien écrire vous pouvez utiliser ce blog qui vous décrit les bonnes et mauvaises pratiques


 

source : https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md



Gestion de Mémoire


Ensuite, il est important de regarder la gestion de la mémoire. Même si nos machines sont de plus en plus performantes il est nécessaire de connaître l’empreinte mémoire de nos algorithmes afin de déterminer si je dois découper mes images en blocs de 256x256 ou 64x64 (pour la reconnaissance de visages). Pour cela il existe un livre (1200 pages tout de même: https://prodotnetmemory.com/) sur la gestion de la mémoire. Cet ouvrage vous fournit également une liste d'outils pour analyser l'utilisation de la mémoire par votre programme.


 

source : https://prodotnetmemory.com/data/netmemoryposter.pdf


Ensuite vous pouvez comparer les performances de vos algorithmes entre .Net / . Net core avec ce framework (......) dont le but est de réaliser un ensemble de tests et d’en sortir un tableau comparatif


Validation des arguments


Par ailleurs, le contrôle des arguments étant nécessaire dans nos programmes/ algorithmes. On peut économiser du temps ici aussi. https://reubenbond.github.io/posts/dotnet-perf-tuning décrit comment effectuer ces contrôles pour avoir un code natif généré performant. Le gain est ici encore infime, quelques nano secondes mais des petits gains un peu partout ont forcement un impact sur l'ensemble.



Méthodes, Debug/Release, Fwk en preview


Nos algorithmes étant constitués de classes et de méthodes, il est également bon de savoir que chaque typologie de méthodes possède des écarts en terme de performance. En effet optimiser un algorithme est important, mais il faut savoir que de mettre "static" ou "virtual" sur une méthode a un impact. Cet impact peut être mesurable dès lors que notre algorithme tourne plusieurs heures... (oui, cet écart est infime si la méthode est appellée quelques milliers de fois, mais quand on arrive sur des millions, l'écart se creuse)

Éric Gunnersson a fait un comparatif il y a quelques années (le lien vers son article ne fonctionne plus... trop ancien sans doute). J'en ai repris le principe, à savoir mesurer l'ecart entre les différentes types de méthodes :

  1. Méthode d’instance​
  2. Méthode d’interface​
  3. Méthode virtuelle​
  4. Méthode d’interface virtuelle​
  5. Méthode statique​
  6. Méthode Reflection.InvokeMember​
  7. Méthode Reflection.MethodInfo.Invoke​
  8. Méthode déléguée*​
  9. Méthode déléguée générée dynamiquement*​
  10. Méthode d’interface sur une classe générée dynamiquement*​
  11. Méthode virtuelle sealed​


à l'origine Eric Gunnerson avait fait une application en Windows Forms


En la reprenant, j'ai voulu comparer cette même application sur .NetFramework et .Net Core 3 (preview). J'ai donc rendu cette application compatible avec .Net Core 3.


Autant vous le dire de suite, rien ne sert de comparer .NetCore et .Net framework ici (puisque'il s'agit d'une preview... les résultats sont sans appel). En effet en Preview le code nest pas optimisé, il est donc evident qu'il ne faut pas utiliser une preview en production. En revanche il est interessant de regarder les performances Debug/Release et que globalement les appels directs (static, virtuel, sealed, via interfaces ou non) sont beaucoup plus rapide que les appels de type reflection.


à l'extrême static et sealed sont les plus rapide (...un programme complet en static ça s'écrit, mais pour les tests unitaires ça devient compliqué ;-) )


Conclusion


  • Essayer le plus souvent de marquer "Sealed" vos méthodes virtuelles.
  • Eviter de déployer vos dlls compilées en Debug
  • Eviter d'utiliser des frameworks en preview, ou uniquement à but de POCs
  • L'optimisation se joue à tous les niveaux. De la machine jusque la ligne de votre code en passant par le choix du runtime utilisé !





Commentaires :

Aucun commentaires pour le moment


Laissez un commentaire :

Réalisé par
Expaceo