Il semble que l’optimisation soit un art perdu de nos jours. N’y a-t-il pas eu un moment où tous les programmeurs ont tiré chaque once d’efficacité de leur code? Le fait souvent en marchant cinq milles dans la neige?
Dans le but de ramener un art perdu, quels sont les conseils que vous connaissez pour les changements simples (ou peut-être complexes) visant à optimiser le code C # / .NET? Comme il s’agit d’une chose si vaste qui dépend de ce que l’on essaie d’accomplir, cela aiderait à fournir un contexte avec votre conseil. Par exemple:
SsortingngBuilder
. Voir le lien en bas pour les mises en garde à ce sujet. ssortingng.Compare
pour comparer deux chaînes au lieu de faire quelque chose comme ssortingng1.ToLower() == ssortingng2.ToLower()
Le consensus général jusqu’ici semble mesurer est la clé. Ce genre de chose manque le point: mesurer ne vous dit pas ce qui ne va pas ou que faire si vous rencontrez un goulot d’étranglement. J’ai rencontré le goulot d’étranglement de la concaténation de chaînes une fois et je ne savais pas quoi faire à ce sujet, donc ces conseils sont utiles.
Mon point pour poster même ceci est d’avoir une place pour les goulots d’étranglement courants et comment ils peuvent être évités avant même de les rencontrer. Il ne s’agit même pas nécessairement du code plug-and-play que tout le monde devrait suivre aveuglément, mais plutôt de comprendre que la performance doit être envisagée, au moins quelque peu, et qu’il existe des pièges courants à rechercher.
Je peux voir cependant qu’il pourrait être utile de savoir pourquoi une astuce est utile et où elle devrait être appliquée. Pour le conseil SsortingngBuilder
j’ai trouvé l’aide que j’ai faite il y a longtemps sur le site de Jon Skeet .
Il semble que l’optimisation soit un art perdu de nos jours.
Une fois par jour, la fabrication de microscopes, par exemple, était pratiquée comme un art. Les principes optiques étaient mal compris. Il n’y avait pas de standardisation des pièces. Les tubes, les engrenages et les lentilles devaient être fabriqués à la main par des travailleurs hautement qualifiés.
Ces microscopes sont aujourd’hui produits en tant que discipline d’ingénierie. Les principes sous-jacents de la physique sont extrêmement bien compris, les pièces disponibles dans le commerce sont largement disponibles et les ingénieurs en construction de microscopes peuvent faire des choix éclairés quant à la meilleure manière d’optimiser leur instrument pour les tâches à exécuter.
Cette parsing de performance est un “art perdu” est une très bonne chose. Cet art était pratiqué comme un art . L’optimisation doit être envisagée pour ce qu’elle est: un problème d’ingénierie pouvant être résolu par l’application minutieuse de principes techniques solides.
Au cours des années, on m’a demandé des dizaines de fois pour ma liste de “trucs et astuces” que les gens peuvent utiliser pour optimiser leur vbscript / leur jscript / leurs pages de serveur actives / leur code VB / C #. Je résiste toujours à cela. Mettre l’accent sur les «trucs et astuces» est exactement la mauvaise façon d’aborder les performances. De cette manière, le code est difficile à comprendre, difficile à raisonner, difficile à gérer, ce qui n’est généralement pas plus rapide que le code simple correspondant.
La bonne façon d’aborder la performance est de l’aborder comme un problème d’ingénierie comme tout autre problème:
C’est comme si vous résolviez tout autre problème d’ingénierie, comme l’ajout d’une fonctionnalité – définissez des objectives centrés sur le client pour la fonctionnalité, suivez les progrès de l’implémentation solide, résolvez les problèmes en les analysant soigneusement, continuez d’itérer jusqu’à vous expédiez ou échouez. La performance est une fonctionnalité.
L’parsing de la performance sur des systèmes modernes complexes exige de la discipline et de se concentrer sur des principes techniques solides, et non sur un sac plein d’astuces qui sont étroitement applicables à des situations insignifiantes ou irréalistes. Je n’ai jamais résolu un problème de performance réel en appliquant des conseils et des astuces.
Obtenez un bon profileur.
N’essayez même pas d’optimiser C # (vraiment, n’importe quel code) sans un bon profileur. En fait, cela aide énormément à avoir à la fois un échantillonneur et un profileur de traçage.
Sans un bon profileur, vous risquez de créer de fausses optimisations et, surtout, d’optimiser les routines qui ne sont pas un problème de performances en premier lieu.
Les trois premières étapes du profilage doivent toujours être 1) Mesurer, 2) mesurer, puis 3) mesurer ….
Directives d’optimisation:
Comme les processeurs continuent à accélérer le processus, le principal problème dans la plupart des applications n’est pas le processeur, mais la bande passante: la bande passante à la mémoire hors puce, la bande passante sur le disque et la bande passante au réseau.
Commencez par l’extrémité distante: utilisez YSlow pour voir pourquoi votre site Web est lent pour les utilisateurs finaux, puis revenez en arrière et corrigez vos access de firebase database pour qu’ils ne soient pas trop larges (colonnes) et pas trop profonds (lignes).
Dans les très rares cas où il vaut la peine de faire quelque chose pour optimiser l’utilisation du processeur, veillez à ne pas avoir d’impact négatif sur la mémoire: j’ai vu des optimisations où les développeurs essayaient d’utiliser la mémoire pour mettre en cache les résultats. L’effet net a été de réduire la mémoire disponible pour mettre en cache les pages et les résultats de la firebase database, ce qui a rendu l’application beaucoup plus lente! (Voir la règle sur la mesure.)
J’ai également vu des cas où un algorithme «non stupide» et non optimisé a battu un algorithme optimisé «intelligent». Ne jamais sous-estimer à quel point les rédacteurs de compilateurs et les concepteurs de puces ont réussi à transformer le code de bouclage «inefficace» en un code extrêmement efficace pouvant fonctionner entièrement en mémoire sur puce avec traitement en pipeline. Votre algorithme «intelligent» basé sur une arborescence avec une boucle interne non compressée qui compte à rebours que vous pensiez «efficace» peut être battu simplement parce qu’il n’a pas réussi à restr dans la mémoire intégrée lors de l’exécution. (Voir la règle sur la mesure.)
Lorsque vous travaillez avec des ORM, tenez compte des sélections N + 1.
List _orders = _repository.GetOrders(DateTime.Now); foreach(var order in _orders) { Print(order.Customer.Name); }
Si les clients ne sont pas chargés avec impatience, cela peut entraîner plusieurs allers-retours vers la firebase database.
OK, je dois jeter dans mes favoris: Si la tâche est assez longue pour une interaction humaine, utilisez une coupure manuelle dans le débogueur.
Contre. un profileur, cela vous donne une stack d’appels et des valeurs variables que vous pouvez utiliser pour vraiment comprendre ce qui se passe.
Faites cela 10 à 20 fois et vous aurez une bonne idée de ce que l’optimisation pourrait vraiment faire.
Si vous identifiez une méthode comme un goulot d’étranglement, mais que vous ne savez pas quoi faire , vous êtes essentiellement bloqué.
Donc, je vais énumérer quelques choses. Toutes ces choses ne sont pas des balles d’argent et vous devrez toujours définir votre code. Je fais juste des suggestions pour des choses que vous pourriez faire et peut parfois aider. Surtout les trois premiers sont importants.
Les gens ont des idées amusantes sur ce qui compte réellement. Stack Overflow est plein de questions sur, par exemple, est ++i
plus “performant” que i++
. Voici un exemple d’optimisation des performances , et c’est essentiellement la même procédure pour toutes les langues. Si le code est simplement écrit d’une certaine manière “parce que c’est plus rapide”, c’est une supposition.
Bien sûr, vous n’écrivez pas délibérément un code stupide, mais si vous deviniez que cela fonctionnait, les profileurs et les techniques de profilage seraient inutiles.
Dites au compilateur quoi faire, pas comment le faire. Par exemple, foreach (var item in list)
est meilleur que for (int i = 0; i < list.Count; i++)
et m = list.Max(i => i.value);
vaut mieux que list.Sort(i => i.value); m = list[list.Count - 1];
list.Sort(i => i.value); m = list[list.Count - 1];
.
En indiquant au système ce que vous voulez faire, vous pouvez déterminer la meilleure façon de le faire. LINQ est bon parce que ses résultats ne sont pas calculés tant que vous n'en avez pas besoin. Si vous n'utilisez que le premier résultat, il n'est pas nécessaire de calculer le rest.
En fin de compte (et cela s'applique à toute la programmation), minimisez les boucles et minimisez ce que vous faites dans les boucles. Le plus important est de minimiser le nombre de boucles dans vos boucles. Quelle est la différence entre un algorithme O (n) et un algorithme O (n ^ 2)? L'algorithme O (n ^ 2) a une boucle à l'intérieur d'une boucle.
La vérité est qu’il n’existe pas de code optimisé parfait. Vous pouvez cependant optimiser pour une portion de code spécifique, sur un système (ou ensemble de systèmes) connu, sur un type de processeur (et un nombre) connu, une plate-forme connue (Microsoft? Mono ?), Une version framework / BCL connue, une version connue de la CLI, une version connue du compilateur (bogues, modifications de spécification, modifications), une quantité totale et disponible de mémoire connue, une origine d’assemblage connue (disque GAC ? distant?
Dans le monde réel, utilisez un profileur et examinez les bits importants; En général, les choses évidentes impliquent des E / S, tout ce qui implique le threading (encore une fois, cela change énormément entre les versions), et tout ce qui implique des boucles et des recherches, mais vous pourriez être surpris et quel code “évidemment bon” est un énorme coupable.
Je n’essaie pas vraiment d’optimiser mon code, mais parfois je vais utiliser quelque chose comme un réflecteur pour remettre mes programmes à la source. Il est intéressant de comparer ensuite ce que je ne comprends pas avec ce que le réflecteur produira. Parfois, je trouve que ce que j’ai fait sous une forme plus compliquée a été simplifié. Peut ne pas optimiser les choses mais m’aide à voir des solutions plus simples aux problèmes.