Introduction : pourquoi la performance en C# est importante
C# et la plateforme .NET sont des outils puissants pour créer des services web à forte charge, des applications de bureau et des jeux sous Unity. Cependant, même le code le plus élégant peut fonctionner lentement si l'on ne prend pas en compte les particularités du CLR (Common Language Runtime), du garbage collection (GC) et des mécanismes de compilation JIT.
Dans cet article, nous allons analyser les méthodes clés d'optimisation des performances des applications C# qui vous aideront à réduire le temps de réponse, diminuer la consommation mémoire et augmenter le débit du système. Tous les conseils sont accompagnés d'exemples de code pratiques.
1. Gestion de la mémoire et garbage collection (GC)
L'une des principales caractéristiques de .NET est la gestion automatique de la mémoire. Mais une mauvaise utilisation des objets entraîne des collectes fréquentes, ce qui provoque des "pauses" (pause) de l'application.
1.1. Évitez les allocations dans les chemins critiques
Essayez de ne pas créer de nouveaux objets à l'intérieur de boucles ou de méthodes fréquemment appelées. Utilisez plutôt des pools d'objets ou réutilisez des instances.
// Mauvais : un nouveau StringBuilder est créé à chaque itérationfor (int i = 0; i < 1000; i++){ var sb = new StringBuilder(); sb.Append(i);}
// Bon : on utilise un pool ou on réutilisevar sbPool = new StringBuilder();for (int i = 0; i < 1000; i++){ sbPool.Clear(); sbPool.Append(i);}1.2. Utilisez des structures au lieu de classes pour les petites données
Les structures (struct) sont stockées sur la pile et ne créent pas de charge pour le GC. Mais attention : les grandes structures (plus de 16 octets) peuvent être copiées lentement.
public struct Point{ public int X; public int Y;}
// Maintenant, l'appel de méthode ne crée pas d'objet dans le tasvoid ProcessPoint(Point p) { /* ... */ }1.3. Activez le mode Server GC pour les applications serveur
Par défaut, dans les applications console, le Workstation GC est utilisé. Pour les services web (ASP.NET Core), passez au Server GC dans le fichier csproj :
<PropertyGroup> <ServerGarbageCollection>true</ServerGarbageCollection></PropertyGroup>2. Optimisation du travail avec LINQ et les collections
LINQ est un outil pratique, mais potentiellement lent si l'on ne connaît pas ses "pièges".
2.1. Évitez les énumérations multiples
Chaque appel à .Count(), .ToList() ou .Any() peut réexécuter la requête. Stockez le résultat dans une variable.
// Mauvais : deux parcours de la collectionif (items.Where(x => x.IsActive).Count() > 0) { /* ... */ }var activeList = items.Where(x => x.IsActive).ToList();
// Bon : un seul parcoursvar activeItems = items.Where(x => x.IsActive).ToList();if (activeItems.Count > 0) { /* ... */ }2.2. Utilisez des collections spécialisées
Pour une recherche fréquente par clé, utilisez Dictionary<TKey, TValue> plutôt que List<T>. Pour les opérations "premier entré, premier sorti" — Queue<T>.
// Recherche rapide : O(1) au lieu de O(n)var dict = new Dictionary<int, string>();dict.Add(1, "one");if (dict.ContainsKey(1)) { /* ... */ }2.3. Remplacez LINQ par des boucles dans les sections critiques
Pour les opérations simples (somme, filtrage), une boucle for ou foreach peut être 2 à 3 fois plus rapide que LINQ.
// LINQ (lent)int sum = numbers.Sum();
// Boucle (rapide)int sum = 0;for (int i = 0; i < numbers.Length; i++){ sum += numbers[i];}3. Programmation asynchrone et réduction des blocages
Une bonne utilisation de async/await permet de ne pas bloquer les threads, ce qui est crucial pour la scalabilité.