Comment éviter «l'intuition de la mauvaise optimisation du développeur»?


22

J'ai vu sur un article qui mettait en avant cette déclaration:

Les développeurs aiment optimiser le code et pour une bonne raison. C'est tellement satisfaisant et amusant. Mais savoir quand optimiser est beaucoup plus important. Malheureusement, les développeurs ont généralement une horrible intuition quant à l'emplacement réel des problèmes de performances dans une application.

Comment un développeur peut-il éviter cette mauvaise intuition? Existe-t-il de bons outils pour trouver quelles parties de votre code ont vraiment besoin d'être optimisées (pour Java)? Connaissez-vous des articles, des conseils ou de bonnes lectures à ce sujet?


1
Cela revient à "Comment puis-je éviter [de me fier] à des intuitions [lors de la prise de décisions]?" Simple: vous vérifiez avec des faits et des données. Donc, dans le cas de l'optimisation, du point de vue d'un développeur: vous faites un benchmark.
haylem

Réponses:


44
  • Utilisez un bon profileur pour identifier les méthodes coûteuses.
  • Documentez combien de temps les points chauds ont réellement pris.
  • Écrivez une implémentation plus rapide des points chauds
  • Documentez combien de temps les points chauds prennent maintenant, en espérant ne pas en faire des points chauds

Essentiellement, vous devez être en mesure de prouver aux autres où était le problème et que ce changement l'a fait disparaître.

Ne pouvant prouver une amélioration, se qualifie - à mon avis - pour un retour immédiat à la version originale.


51
Ou pour le dire encore plus simplement: "Afin d'éviter une mauvaise intuition d'optimisation, ne pas utiliser l'intuition. Mesurer."
Kyralessa

6
C'est pourquoi la vôtre est une réponse et la mienne n'est qu'un commentaire. : P
Kyralessa

2
@Thomas, si vous jouez avec la lisibilité et la maintenabilité, vous ne regardez pas exactement les problèmes de performances, n'est-ce pas?

3
@Thomas, je ne suis pas d'accord. Même dans les spécifications, vous devez tester à nouveau le nouveau code à fond. Ce n'est pas nécessaire pour l'ancien code. Revenir.

2
@ Thorbjørn Après l'optimisation des performances, vous devez également retester soigneusement le nouveau code. Gagner du temps ou de la mémoire n'a aucun sens si vous avez introduit un défaut.
Thomas Owens

10

La seule façon de savoir où optimiser est de profiler votre code. Au lieu d'apporter des modifications qui, selon vous, apporteront un avantage, sachez avec certitude où se trouve le code le moins performant et commencez par là.

Java rend cela assez facile avec l' outil VisualVM , qui a été fourni avec les dernières versions du kit de développement Java (JDK). L'idée est de savoir quelles méthodes sont les plus appelées et dans quelles méthodes vous passez le plus de temps, à la fois dans votre code et dans des bibliothèques externes. Vous pouvez également obtenir des données de performances sur la récupération de place afin de régler votre collecteur et d'ajuster l'espace de tas min / max requis par votre application.


VisualVM n'est pas dans le JRE, seulement le JDK.

1
@ Thorbjørn Ravn Andersen Bon appel. Je devrais clarifier. Cependant, si vous faites du développement Java, vous avez généralement le JDK installé (bien que vous puissiez exécuter OpenJDK ou similaire - je ne sais pas si ceux-ci sont fournis avec VisualVM).
Thomas Owens

1
Je change très fréquemment d'espaces de travail dans Eclipse qui par défaut est alors le JRE qui a lancé Eclipse. Comme il est beaucoup plus facile d'installer JRE que JDK, nous avons lentement migré vers un processus de génération de fourmis qui inclut le compilateur Eclipse et peut donc s'exécuter sur le JRE standard. Par conséquent, ces jours-ci, vous pouvez réellement travailler sans JDK. VisualVM peut être téléchargé séparément, ce qui le rend plus facile à utiliser avec un versino Java donné, car sous Windows, les JVM 64 bits ne peuvent pas se connecter à des JVM 32 bits et vice versa.

9

Comme quiconque ici parle de profileurs, je me concentrerai sur cette partie de la question.

Comment un développeur peut-il éviter cette mauvaise intuition?

Toi. faire. ne pas. Au lieu de cela, vous n'optimisez jamais tôt .
Répétez-le encore et encore et encore, car c'est un mantra religieux.

Vous vous retrouverez à faire cela et découvrirez que vous n'auriez pas dû.
Et puis encore.
Et encore.

L'optimisation précoce est l'un des péchés capitaux des programmeurs .

Les outils et les trucs font partie de l' optimisation ultérieure qui est un métier établi .


Optimisation précoce du «code alambiqué», c'est sûr. Choisir des algorithmes et / ou des structures de données qui correspondent à votre problème et (avec votre charge de traitement attendue) ont de bonnes caractéristiques de performance est quelque chose qui doit être fait avant de commencer à écrire du code.
Vatine du

@Vatine Oui, j'y suis allé. Non, tout simplement pas. Faites ce qui correspond à votre carte mentale du problème à résoudre. Ce pourrait être l'algorithme le plus performant , et je vous le souhaite, ce n'est pas obligatoire.
ZJR

cela me semble être le principe YAGNI - Vous n'en aurez PAS besoin!
EL Yusubov

7

Ces outils sont appelés profileurs . Vous pouvez les utiliser pour mesurer réellement quelle (s) partie (s) de votre programme prend le plus de temps à exécuter, alors où concentrer vos efforts de réglage.

Il est également important de mesurer à nouveau après les modifications, pour vérifier que vos modifications ont l'effet escompté.


5

Regardez également la quantité de mémoire utilisée par votre programme, pas seulement sa vitesse ou sa durée d'exécution.

De nombreux codeurs qui travaillent avec des langages récupérés comme Java ont l'impression erronée que la récupération de place empêche les fuites de mémoire. Ce n'est pas le cas. Si vous détenez une référence à un objet dont vous n'avez plus besoin, il ne sera pas collecté et fuira donc.

J'ai vu des applications Web Java qui fuyaient tellement qu'elles faisaient tourner leur serveur sans espace d'échange!

Si vous utilisez à la fois un profileur d'exécution et une sorte de profileur de mémoire, vous apprendrez à écrire du code plus rapidement et plus facilement de manière intuitive. Cela a pour effet que votre code est plus susceptible de s'exécuter rapidement du premier coup.


1

mon remède est de commencer par obtenir des réponses claires à deux questions:

  1. comment mesurer les performances (p. ex. mesurer le temps de chargement des données )
  2. quelle est la valeur cible (par exemple, les données se chargent en 3 secondes ou moins avec une confiance de 95% )

Truc appris ci-dessus par des gars de l' équipe de tigre qui ont déjà été invités à enregistrer une version cassée de notre produit. Cette version a été interrompue pour des raisons de performances, elle pourrait faire perdre à la société un client stratégique, ce qui justifiait l' implication des gars du tigre (assez chère) J'ai été chargé de les aider à clarifier les détails du projet; également utilisé cette occasion pour en apprendre un peu ou deux sur les performances.


1

Ce que j'ai trouvé est le meilleur antidote à l'optimisation prématurée est cette méthode .

Une fois que vous l'avez utilisé pour accélérer du code (comme dans cet exemple ), il devient une dépendance à part entière, et vous comprenez que le premier principe de l'optimisation des performances ne consiste pas à modifier le code, il trouve le problème .

La véritable optimisation est l'optimisation prématurée, car la chasse pour nourrir votre famille consiste à tirer des boîtes de conserve. Il s'agit de trouver la carrière.


1
Et malheureusement, vous ne pouvez ramener que 200 livres à votre famille, alors ne tirez pas sur les écureuils toute la journée.
Jordan

1

Vieille question, mais je proposerai cette réponse qui diffère considérablement des autres.

Les grandes opportunités de gains de performances proviennent du traitement parallèle. Essayez de concevoir votre code pour tirer parti de plusieurs threads. (Même si, pour simplifier, vous ne le faites pas dans la version 1). Peu de conjectures ou d'intuition nécessaires.

Tout le reste est une optimisation prématurée et nécessite votre intuition, ce qui est souvent faux.


Vraiment un bon point. À l'époque, vous pouviez compter sur des processeurs beaucoup plus rapides toutes les quelques années. Maintenant, vous ne devez vous attendre qu'à plus de processeurs.
JimmyJames

0

Votre intuition peut s'améliorer avec le temps. Je jetterais cela, peut-être un peu controversé, mais au cours de nombreuses années d'utilisation de VTune et CodeAnalyst et maintenant de CodeXL, je dirais que je suis beaucoup plus précis dans mes intuitions qu'auparavant quant à l'emplacement des points d'accès, au moins pour le point où je ne suis plus complètement pris au dépourvu lorsque je profile un code. Cela ne signifie pas que j'essaie d'optimiser les choses à l'aveuglette.

Le profilage a en fait accru ma dépendance vis-à-vis des profileurs, et non diminué. Je dis simplement que je peux plus facilement anticiper les résultats du profilage dans une certaine mesure et, en outre, éliminer avec succès les points chauds et améliorer le temps nécessaire pour terminer l'opération utilisateur sans prendre de coups aveugles dans le noir et manquant (quelque chose que vous peut faire même lorsque vous utilisez un profileur jusqu'à ce que vous commenciez à comprendre non seulement ce que sont les hotspots, mais pourquoi ils sont exactement des hotspots en ce qui concerne, disons, les échecs de cache).

Cependant, ce n'est que lorsque j'ai commencé à utiliser des profileurs que j'ai commencé à améliorer cette intuition. L'une des raisons est que si vous connaissez bien votre code, vos intuitions peuvent être correctes par rapport aux points d'accès les plus importants et les plus évidents, mais pas toutes les subtilités entre les deux. Naturellement, si vous avez une opération utilisateur qui prend une heure et qu'il existe un algorithme de complexité quadratique béant traitant une entrée couvrant cent mille éléments, vous pouvez probablement sortir riche en jouant toutes vos économies sur l'idée que c'est la complexité quadratique algorithme en faute ici. Mais cela ne vous donne aucun aperçu détaillé ou, par exemple, vous permet de savoir exactement ce qui ne contribue pas au temps.

Il y a tellement de valeur à avoir lorsque vous commencez à créer des profils et à voir où toutes les choses que vous pensiez avoir été un plus grand contributeur de temps ne contribuaient pas beaucoup de temps; pas les sources évidentes béantes d'inefficacités mais celles que vous soupçonniez auraient pu être légèrement inefficaces mais, après profilage, réalisant qu'elles ont à peine contribué à tout moment. Et c'est potentiellement là où vous obtenez le plus intuitif que vous vous trompez dans tous ces domaines subtils où il n'est pas évident de savoir combien de temps vous passez.

L'intuition humaine au-delà de la complexité algorithmique évidente commencera souvent incorrectement parce que ce qui est efficace pour la machine et ce qui est efficace pour l'esprit humain sont très différents. Il ne vient pas si intuitivement au début de penser aux hiérarchies de mémoire allant des registres au cache CPU à la DRAM au disque. Il ne vient pas intuitivement de penser que l'arithmétique redondante peut être plus rapide que de faire plus de branchements ou d'accès à la mémoire d'une table de recherche pour ignorer certains travaux de traitement. Nous avons tendance à penser en termes de travail à faire tout en actualisant des choses comme le coût de la prise de décisions et les charges de mémoire et les magasins. Ce qui est efficace pour le matériel est souvent très contre-intuitif de manière à briser toutes vos hypothèses humaines au départ,

Là où l'amélioration de cette intuition peut aider, grâce au profilage, c'est la conception d'interface . Les conceptions d'interface sont très coûteuses à changer avec le recul, les coûts augmentant proportionnellement au nombre de places en fonction de cette interface. Lorsque vous commencez à améliorer votre intuition, vous pouvez commencer à concevoir des interfaces mieux la première fois de manière à laisser une marge de manœuvre pour une optimisation future sans modifications de conception coûteuses. Encore une fois cependant, cette intuition est quelque chose que vous développez généralement, et continuez à développer indéfiniment, en ayant toujours ce profileur en main.


0

Les profileurs aident à corriger la mauvaise intuition en matière de code. Étant donné la quantité de matériel prédite ces jours-ci, il n'est pas humainement pratique de prédire les performances de votre code, mais cela était encore vrai à l'époque de Knuth il y a tant de décennies qui préconisaient que les profileurs soient inclus dans les outils standard de développement pour corriger le problème. nature "insensée à cent pour cent" des développeurs. Mais je vais emprunter une voie très différente avec cette réponse, étant donné à quel point les réponses sont complètes à d'autres égards et dire que la compréhension par l'utilisateur final est l'autre "solution".

J'ai vu, dans mon expérience personnelle, un développeur particulièrement brillant (mais avec des angles morts béants sur la façon dont les utilisateurs utilisent réellement le logiciel) optimisant un algorithme de subdivision avec profileur à la main (très bon et coûteux et complet: VTune d'Intel avec graphique des appels) échantillonnage au-dessus des profileurs GPU) pour les maillages obtenir des résultats étonnants avec des milliards de facettes sur le GPU lors de la subdivision de primitives simples comme des cubes avec 6 polygones cage / entrée. Sauf qu'il l'a réglé et ajusté par rapport à ce cas de test qui ne ressemblait à aucun cas d'utilisation réel (les utilisateurs ne veulent pas un milliard de facettes d'un cube subdivisé commençant à ressembler à une sphère parfaite, leurs entrées de subdivision ont tendance à être des choses comme des personnages et des véhicules et autres intrants complexes).

Curieusement, je suis allé plus loin avec un cerveau à moitié aussi fonctionnel que lui et sans doctorat à mon actif dans ma carrière pour la simple raison que je comprenais ce que les utilisateurs voulaient, ce que le marketing voulait, ce que les designers voulaient. Je ne saurais trop insister sur l'utilité de pouvoir se mettre dans l'état d'esprit et à la place de l'utilisateur et regarder votre logiciel et ce qu'il doit faire en tant qu'utilisateurs réels tout en s'efforçant de vous dissocier des efforts que vous mettez en construisant ce que vous avez construit et en le regardant avec une nouvelle paire d'yeux. J'ai même rencontré du développeur ci-dessus que c'est une chose impossible à faire; il pensait que j'étais coupable d'avoir un genre d'ego similaire à celui de tous les développeurs techniquement avertis mais inconscients des utilisateurs, et je lui ai constamment prouvé le contraire lorsque les utilisateurs et les concepteurs affluent vers moi pour parler exactement de ce qu'il faut faire. Cela semble très égoïste, mais je vais équilibrer cela avec l'avertissement que je ne suis pas un codeur si brillant, mais je comprends ce que veulent les utilisateurs et les concepteurs, et cela m'a particulièrement favorisé dans mon domaine où cela semblait être particulièrement rare qualité pour une raison quelconque. En tant que programmeurs, nous sommes probablement plus habitués à tester les tests qu'à comprendre et socialiser avec des gens ordinaires et non techniques.

Il y a donc un profilage et une mesure correcte, mais il y a également le besoin fondamental de s'assurer que vous mesurez une opération avec le type d'entrées que les utilisateurs réels vont réellement fournir à l'application. Sinon, vous pouvez même avoir VTune ou CodeAnalyst ou gprof ou tout autre profileur en main, tout en essayant d'optimiser les points chauds par rapport à ce qui peut sembler être un cas de test normal pour le développeur mais obscur pour les utilisateurs, finissent par pessimiser le cas d'utilisation courant en faveur d'un cas d'utilisation obscur que peu d'utilisateurs, le cas échéant, envisagent de postuler.

À la fin de la journée, toutes les impraticalités que nous avons tendance à porter en tant que développeurs peuvent être mises en balance avec le marteau de fer de ce qui rend les utilisateurs vraiment assez heureux sans résoudre la faim dans le monde, et le besoin pratique d'obtenir de l'argent afin que nous puissions payer le loyer ou acheter de la bière ou regardez les femmes nues ou tout ce que vous voulez / devez faire. Tout le reste va potentiellement à l'encontre de ce besoin commercial fondamental, et tout développeur si noble, si héroïque, afin d'oublier qu'il s'agit de gagner de l'argent et, en fin de compte, de satisfaire les utilisateurs pour les amener à payer pourrait bien se ramener sur terre et désactivez le mode divin créant des mondes virtuels en faveur du besoin du monde réel d'expédier simplement et d'obtenir de l'argent pour la nourriture. On peut se perdre dans les métriques et les pratiques logicielles mais fondamentalement ça '

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.