Quand dois-je me soucier de la performance?

16

Pendant la plus longue période dans des endroits comme le canal IRC de Java , SO et d'autres endroits, on m'a dit quelque chose du genre: "Inquiétez-vous de l'apparence du code et de sa lisibilité / compréhensibilité maintenant, et des performances plus tard si absolument nécessaire". Donc, depuis très longtemps, je n'ai pas vraiment été OCD sur les performances de mes petites applications de bureau ou Web, supprimant simplement l'inefficacité inefficace.

La plupart des réponses sont «Qu'en est-il de l'évolutivité?». C'est un point légitime, mais si mon application n'a été conçue que pour analyser, disons, des fichiers de 10 000 lignes, dois-je faire de mon code un gâchis pour le petit pourcentage de personnes qui vont fourrer dans un fichier de 1 000 000 de lignes?

Ma question principale est de savoir quand devrais-je échanger des moyens faciles mais quelque peu inefficaces de faire des tâches pour de grosses bêtes géantes et compliquées qui font les choses extrêmement rapidement mais détruisent tous les moyens possibles de mise à niveau et rendent le code excessivement difficile et sujet à réécriture de toute façon par le prochain développeur?

TheLQ
la source

Réponses:

23

Inquiétez-vous des performances lorsque cela devient un problème.

Si vous écrivez une petite application pour traiter 10 000 fichiers de ligne et que vous obtenez un fichier de 1 000 000 de ligne tous les 100 fichiers, cela n'a probablement pas d'importance que le traitement de ce fichier prenne plus de temps. Cependant, si vous obtenez régulièrement des fichiers 5 à 10 fois plus volumineux qu'initialement et que votre application prend trop de temps pour faire son travail, vous commencez le profilage et l'optimisation.

Maintenant, j'ai dit "trop ​​de temps pour faire son travail". Il appartient à l'utilisateur ou à l'organisation sponsor de décider. Si je fais une tâche et qu'il me faut 5 minutes pour faire quelque chose quand il m'en a fallu 3 sans le logiciel ou avec un outil différent, je déposerais probablement un rapport de bogue ou une demande de maintenance pour l'améliorer.

Si vous êtes l'utilisateur, le temps que vous voulez que votre logiciel prenne pour faire son travail dépend de vous - vous seul pouvez décider si vous voulez que cela se fasse plus rapidement ou si vous êtes prêt à attendre plus longtemps pour avoir un code plus lisible.

Thomas Owens
la source
Je commence le profilage et l'optimisation Si 1) le travail prend
trop
10

Ma question principale est de savoir quand devrais-je échanger des moyens faciles mais quelque peu inefficaces de faire des tâches pour de grosses bêtes géantes et compliquées qui font les choses extrêmement rapidement mais détruisent tous les moyens possibles de mise à niveau et rendent le code excessivement difficile et sujet à réécriture de toute façon par le prochain développeur?

Il s'agit généralement d'une fausse dichotomie . Vous pouvez écrire du code merveilleusement efficace, lisible et maintenable. Vous pouvez écrire des tas de désordre merveilleusement inefficaces et incontrôlables.

Lorsque je traite des problèmes de performance, j'essaie généralement de penser au problème commercial que je résous. Comment mon logiciel se comportera-t-il lorsque mes clients l'utiliseront? Les performances de mes applications feront-elles plaisir à Jacob Nielsen ?

Sam Saffron
la source
5
++ FAUX DICHOTOMIE! N'apprendront-ils jamais? Lorsque vous trouvez et corrigez un problème de performances, le code n'est pas seulement plus rapide, il est meilleur . Je regrette seulement de n'avoir qu'une seule voix positive à donner!
Mike Dunlavey
+1 pour avoir écrit que c'est généralement une fausse dichotomie ... pas toujours, mais généralement.
Dan Rosenstark
1
-1 pour l'écriture, c'est généralement une fausse dichotomie - le fait est, c'est généralement correct, et seulement dans de rares cas une fausse dichotomie. Au cours de plus de 30 ans de ma carrière en programmation, j'ai vu trop d'optimisations de performances "bien intentionnées" qui ont en fait rendu le code plus difficile à comprendre et à maintenir (et souvent optimisé quelque chose qui était totalement inutile à optimiser).
Doc Brown
5

Un truisme que j'ai ramassé en étudiant les microprocesseurs à l'université qui est resté avec moi: "Rendez le cas commun rapide. Rendez le cas rare correct."

Tant que vous n'avez qu'un petit pourcentage d'utilisateurs étouffant votre code avec une entrée de deux ordres de grandeur supérieure à ce qu'il était censé gérer, ne le transpirez pas. Assurez-vous qu'il gère correctement l'entrée s'ils lui donnent suffisamment de temps et ne laisse rien corrompu dans l'inutilité s'ils tuent le travail avant qu'il ne se termine.

Mais, une fois de plus en plus de gens commencent à l'utiliser de cette façon (ou commencent à vous dire "Vous savez, j'aimerais beaucoup utiliser cet outil que vous avez écrit sur mes rapports hebdomadaires TPS, mais cela prend toute la journée"), c'est là vous commencez à envisager la facilité de maintenance pour des gains de performances.

BlairHippo
la source
1

Ma question principale est de savoir quand devrais-je échanger des moyens faciles mais quelque peu inefficaces de faire des tâches pour de grosses bêtes géantes et compliquées qui font les choses extrêmement rapidement mais détruisent tous les moyens possibles de mise à niveau et rendent le code excessivement difficile et sujet à réécriture de toute façon par le prochain développeur?

«S'inquiéter de l'apparence du code et de sa lisibilité / compréhensibilité maintenant, et des performances plus tard si absolument nécessaires» est la solution la plus simple et généralement inutile. une bonne conception sera facile à entretenir, facile à lire et efficace.

la performance est un élément commun d'une bonne conception. si votre programme est lent et inutile, il n'est vraiment pas réutilisable. lorsque vous devez corriger ce désordre, vous forcez les mises à jour sur vos clients, à moins qu'il ne soit trop temps de les mettre à jour. ce programme lent devient le gros gâchis trop coûteux à améliorer. puis ils choisissent une alternative car elle ne répond pas à leurs besoins. le diagnostic, la mise à jour et la gestion des effets secondaires des améliorations apportées à une mauvaise conception l'emportent souvent sur le temps de développement initial de l'écriture pour être efficace, fonctionner correctement et avoir une bonne conception générale. ce programme est hautement réutilisable et nécessite peu de maintenance (win).

ainsi, la réponse courte à votre question est "ne gaspillez pas. écrivez pour la réutilisation. il est normal d'être paresseux lors du prototypage / développement de preuves de concepts, mais n'utilisez pas ce prototype pour le code de production.".

soyez conscient et évitez les conceptions inutiles lorsque vous écrivez des programmes de production et des programmes que vous avez l'intention de réutiliser. pendant l'implémentation est le moment idéal pour écrire votre programme afin de ne pas être un gaspillage - vous avez une idée claire des détails et de son fonctionnement, et il est vraiment pénible et inefficace de le réparer une fois qu'il est écrit. beaucoup de gens croient qu'un peu de profilage (peut-être) à la fin ou s'il y a un problème est adéquat, alors que cela prend généralement trop de temps pour être repensé / modifié et que les inefficacités sont si nombreuses et si répandues que vous ne comprenez pas le programme bien basé sur les résultats d'un profil. cette approche prend peu de temps lors de l'implémentation et (en supposant que vous l'avez fait suffisamment de fois) se traduit généralement par une conception plusieurs fois plus rapide et réutilisable dans de nombreux autres contextes. ne pas gaspiller, choisir de bons algorithmes, réfléchir à vos implémentations et réutiliser les bonnes implémentations sont tous des éléments d'une bonne conception; tousaméliore la lisibilité, la maintenabilité et la réutilisation plus souvent que cela ne le blesse.

Justin
la source
0

J'essaie de rendre le code lisible - les performances sont maudites.

Quand et si le code s'avère trop lent, je le refactoriserai pour être plus rapide. Habituellement, le processus de refactorisation est suivi de nombreux commentaires, car le code a tendance à être moins lisible.

Josip Medved
la source
0

Hum - Jamais?

Sérieusement, le code doit toujours être écrit de manière à être facilement compris et maintenu.

En ce qui concerne le moment de traiter les problèmes de performances, traitez-les une fois que vous les avez identifiés, ne pré-optimisez pas votre code, car vous devinerez simplement où se trouvent les problèmes de performances.

Si votre code est écrit de manière à être clair, concis, compréhensible et maintenable, vous ou un autre programmeur ne devriez avoir aucun problème à refactoriser le code pour le rendre plus efficace.

Noah Goodrich
la source
3
Je ne suis pas d'accord avec ça. Une exigence de performance est une exigence non fonctionnelle valide pour un système.
Thomas Owens
Techniquement, s'il existe une exigence clairement définie liée aux performances, on peut dire que vous avez identifié un problème de performances et que vous devez en tenir compte dans votre solution. Ce dont je parle, c'est de devenir intelligent à l'avance afin d'éviter des problèmes «potentiels» non spécifiques.
Noah Goodrich
Ah. Oui, vous avez absolument raison dans ce cas. Vous ne vous inquiétez pas des possibilités car il y en a tellement, mais concentrez-vous sur ce que vous savez.
Thomas Owens
0

J'écris normalement du code pour être lisible avant tout. Si, et seulement si, je trouve que le programme est trop lent pour faire son travail, dois-je profiler et optimiser. Cela dit, il n'y a rien de mal à prendre l'habitude d'effectuer des optimisations courantes qui n'affectent pas la lisibilité de votre code. Autrement dit, si un morceau de code peut être écrit de deux manières lisibles également (ou presque également), choisissez celui qui est généralement le plus rapide.

Par exemple, en Python, les compréhensions de liste (ou expressions de générateur) ont tendance à être plus rapides que la forboucle équivalente , donc j'utilise des compréhensions de liste là où je peux, si elles n'affectent pas la lisibilité (par exemple, je ne nidifie pas les compréhensions de liste si Je peux l'éviter et utiliser une boucle for à la place car les compréhensions de listes imbriquées peuvent être difficiles à analyser mentalement).

De même, les types de données immuables ont tendance à être plus rapides que les types mutables, donc j'utilise des types de données immuables lorsque je le peux.

Chinmay Kanchi
la source
0

Si vous travaillez dans des domaines réellement critiques en termes de performances, vous ne pouvez pas reporter l'efficacité après coup. C'est l'une des choses les plus critiques à prendre en compte lors de la conception dès le début dans ces cas et de manière liée à la maintenabilité du résultat final.

Vous ne pouvez pas concevoir et implémenter un serveur à grande échelle et simplement commencer à écrire du code facile et bien documenté qui utilise simplement des fonctions de blocage pour tout avec un verrou de thread global qui verrouille l'ensemble du système pour traiter chaque demande client individuelle sans en mettre aucune pensé que ce soit en état partagé, en conflit de fils et en asynchronicité. C'est une recette pour un désastre et un besoin de repenser et de réécrire la majeure partie du code bien documenté que vous avez écrit de manière à conduire à la base de code la plus difficile à maintenir imaginable, en proie à des conditions de concurrence et des blocages à la suite d'essais pour atteindre l'efficacité requise avec le recul, au lieu d'avoir simplement pensé à des conceptions efficaces, simples et fonctionnelles dès le départ.

Une équipe de développement de jeux en 8 mois de production avec un moteur qui ne fait que 2 images par seconde sur leur matériel le plus costaud avec 32 cœurs tout en ayant tendance à caler pendant 15 secondes chaque fois que l'écran est occupé, il est peu probable d'obtenir instantanément un produit utilisable par juste correction d'un petit hotspot localisé. Il y a des chances que leur conception soit FUBAR d'une manière qui justifie une revisite épique de la planche à dessin et des changements de conception qui pourraient se répercuter dans tous les coins de la base de code.

Avec John Carmack, il a parlé une fois de la façon dont une démonstration technologique doit fonctionner au minimum de centaines à des milliers d'images par seconde afin de l'intégrer dans la production. Ce n'est pas une obsession malsaine pour l'efficacité. Il sait d'emblée que les jeux doivent fonctionner, dans leur intégralité, à plus de 30 FPS pour que les clients le trouvent acceptable. En conséquence, un petit aspect comme un système d'ombre douce ne peut pas fonctionner à 30 FPS, ou bien le jeu dans son ensemble ne peut pas être assez rapide pour fournir la rétroaction en temps réel requise. Il est inutilisable jusqu'à ce qu'il atteigne l'efficacité requise. Dans ces domaines où les performances sont critiques et où il y a une exigence fondamentale d'efficacité, une solution qui ne parvient pas à atteindre une vitesse adéquate n'est en fait pas meilleure qu'une solution qui ne fonctionne pas du tout,. Et vous ne pouvez pas concevoir un système d'ombre douce efficace qui s'exécute à des centaines à des milliers d'images par seconde comme requis pour un moteur de jeu en temps réel à moins que vous ne mettiez en avant une quantité prédominante de réflexion quant à son efficacité. En fait, dans de tels cas, 90% du travail est axé sur l'efficacité car il est trivial de proposer un système d'ombre douce qui fonctionne très bien à 2 heures par image en utilisant le traçage de chemin, mais vous ne pouvez pas vous attendre à le régler pour fonctionner à des centaines d'images par seconde sans changement totalement différent d'approche.

Lorsque l'efficacité est un élément fondamental de la conception d'une application, vous ne pouvez pas vous attendre à une efficacité avec le recul sans perdre considérablement plus de temps que vous n'en avez économisé en l'ignorant, car vous ne pouvez pas vous attendre à réaliser une conception fonctionnelle avec le recul. Personne ne dit: "Je peux remettre la conception à plus tard. Il suffit de bien documenter votre code et vous pourrez trouver une conception appropriée plus tard ." Mais dans les architectures à performances critiques, c'est ce que vous faites efficacement si vous ne faites pas beaucoup attention et réfléchissez à des conceptions efficaces dès le départ.

Maintenant, cela ne signifie pas que vous devez micro-régler vos implémentations dès le départ. Pour les détails de mise en œuvre, il y a beaucoup de place pour itérer vers des solutions plus rapides après la mesure, à condition que la conception n'ait pas besoin de changer, et c'est souvent la façon la plus productive de s'y prendre. Mais au niveau de la conception, cela signifie que vous devez réfléchir suffisamment à la façon dont la conception et l'architecture seront liées à l'efficacité dès le départ.

La principale différence ici est le design. Il n'est pas facile d'apporter de grands changements aux conceptions avec le recul, car les conceptions accumulent des dépendances et les dépendances se briseront si la conception change. Et si une conception doit être raisonnablement efficace ou, dans certains cas, que sa qualité est largement mesurée par son efficacité, alors vous ne devriez pas vous attendre à pouvoir réaliser une conception appropriée après coup. Avec tous les produits compétitifs où l'efficacité est un énorme aspect de la qualité, qu'il s'agisse de systèmes d'exploitation ou de compilateurs ou de processeurs vidéo ou de raytracers ou de moteurs de jeu ou de moteurs physiques, les réflexions sur l'efficacité et les représentations de données ont été méticuleusement pensées dès le début. Et dans ces cas, ce n'est pas une optimisation prématurée de mettre autant de réflexion sur l'efficacité dès le départ. Il plaçait une telle pensée exactement au moment le plus productif pour le faire,


la source