La micro-optimisation

Billet écrit par Eric - 28 décembre 2011, 09:55

Encore un article de Nexen sur la micro-optimisation. Comme on ne peux pas laisser de commentaire sur le site, je profite de mon blog pour en faire un.

Il s'agit du résumé d'un article en anglais sur des conseils d'optimisations pour PHP.

Intérêt de l'optimisation

Je suis très interessé par obtenir des pages qui s'affiche rapidement. Par exemple, sur zenCancan, j'essaye de faire en sorte que la plupart des pages soient calculées en environ 10ms. Je pense que jusqu’à 30 ms on reste dans le domaine de l'acceptable.

A partir de 100ms, en revanche, on entre dans le lent. Je sais à peu prêt tout de suite quand une page commence à dépasser ce temps limite, 100ms semble être mon seuil de perception.

A partir d'une seconde, on entre dans le très lent : aucune page ne devrait mettre plus d'une seconde à être calculé. Les sites dont les pages mettent plus d'une seconde à s'afficher me paraissent beaucoup moins utilisables.

J'affiche toujours, sur tous les sites, à la vue de tous le monde le temps de calcul de la page : il s'agit d'un contrat de qualité passé entre le producteur et le consommateur : je prend le risque de l'informer que j'ai mal fait mon travail ou que j'ai mal calibré mon service. Il s'agit donc en quelque sorte d'un engagement à lui délivrer le contenu en un temps le plus court possible.

Normalement, cette page doit se calculer en moins de 5ms, sauf si je déclenche une foule de commentaire.

Différentes manières de voir l'optimisation

Quel sont les différentes techniques utilisées pour assurer un temps de calcul court ?

Solution 1 :

  • je mets echo à la place de print
  • j'utilise des guillemets pour les clés associative de mes tableaux
  • j'utilise l'opérateur de pré-incrément ++$i à la place du post-incrément $i++

Solution 2 :

  • je mets des index sur mes tables en fonction des requêtes les plus fréquentes
  • j'utilise un cache d'opcode comme APC
  • je mets en cache des parties de pages, notamment si je m'attend à une forte charge

Il y a quelque temps, sur zenCancan, je me suis rendu compte que la page présentant l'ensemble des articles d'un flux commençait à ralentir pour atteindre 50ms.

Est-ce que je me suis dis : vite, je vais chercher dans le code si par hasard, je n'aurais pas utilisé un print à la place d'un echo, ainsi, je gagnerai 8% de performance sur l'appel de cette fonction, soit environ > 0.01ms ?

Non ! J'avais tous simplement oublié un index évident sur l'identifiant du flux et la date de l'article.

Cette solution m'a permis de faire descendre l'affichage de cette page en dessous de 10ms. Soit des pages 5 fois plus rapide.

La micro-optimisation

Ce que présente l'article de Nexen est ce que j'appelle de la micro-optimisation : la perte de temps consacré au développement n'est pas justifiable par le gain effectif de temps sur la calcul de la page.

Ceci dit, les conseils donnés par l'article sont pertinents, mais pas pour l'optimisation !

  1. echo vs print : je pense que tout les développeurs PHP utilisent echo car il a moins de lettre que print.

  2. ne pas utiliser @ : c'est évidemment une bonne pratique. De nombreux bug peuvent être rendu indétectable à cause d'un @ mal placé

  3. initialiser les variables locales : c'est aussi une bonne pratique et surtout, cela produit un notice en cas d'utilisation de la valeur avant son affectation (ex : $i++), c'est donc une faute de programmation de ne pas initialiser les variables.

  4. Utiliser des quotes autour des clés associatives. Initialement, je pensais que l'auteur souhaitait utiliser des quotes à la places des guillemets, ce qui est déjà une micro-optimisation assez ridicule. Mais en fait, c'est bien pire, l'auteur souhaite utiliser des quotes à la places de ... rien du tout et donc profiter du fait qu'une constante inconnue est automatiquement transformée en chaîne de caractère. Heureusement, cette manière hérétique de faire déclenche un notice : c'est donc, là aussi, une très grosse erreur de programmation.

Conclusion

Certes, la critique est facile et l'art est difficile. Cet article est juste un micro-coup de gueule contre la micro-optimisation qui fleurit régulièrement dans les articles sur le PHP.

Et pour continuer sur ce sujet, je vous conseille cet article de Jeff Atwood.

Billet plus ancien : La première page HTML

Commentaires

Gabriel :

"A partir d'une seconde, on entre dans le honteux : aucune page ne devrait mettre plus d'une seconde à être calculé, cela n'est pas professionnel."

N'importe quoi ! Faut arrêter de raconter des conneries et en plus d'épancher sa petite branlette intellectuelle sur un blog. Ah c'est sur qu'afficher une petite page très statique dans le temps c'est pas dur ....

28 décembre 2011, 11:28

Eric :

@Gabriel Effectivement, je me rend compte que mon propos était très excessif. J'ai corrigé en conséquence.

J'ai souvent repris du code PHP/MySQL particulièrement lent et j'ai toujours trouvé que ça n'était pas professionnel de ne pas se préoccuper de la vitesse de rendu des pages. Après, je me fixe une limite à 1s, je ne trouve pas çà particulièrement bas.

28 décembre 2011, 12:48

Cyrano :

@Gabriel, un peu sévère comme réponse.

Les observations soulevées à partir des délais de chargements partent d'un principe qui n'a pas changé et ne changera jamais sur le web : l'internaute est lent et en même temps pressé. Lorsqu'on fait en plus du commerce sur son site, on a d'autant plus intérêt à ce que les pages se chargent très rapidement, sinon, on prend le risque de voir un client potentiel aller chez le concurrent qui, lui, aura pris en compte ce paramètre.

Que les conseils soient ou non valables, répondre en crachant son venin n'a strictement rien de constructif. Peut-être aurait-il été approprié de faire par exemple un compte-rendu sur une des conférences sur ce sujet qu'on a pu entendre au PHP-Tour de Lille en novembre dernier (ou encore faire un lien vers les slides correspondantes), conférence qui nous a montré comment, au gré des montées en charge sur un site on pouvait résoudre des problèmes de rapidité de chargement. Éric ne l'a pas fait, ça ne signifie pas pour autant qu'on doive lui faire le reproche de se soucier du confort de l'internaute à l'intention duquel on publie des pages.

J'ajoute aussi quand même qu'Éric n'a pas parlé de pages statiques, il a parlé de temps de calcul pour construire une page : lorsqu'on reçoit une page dans son navigateur, on ne reçoit que du langage client, mais l'ensemble a été construit en PHP sur le serveur : si on optimise pas un tant soit peu son code PHP/SQL, on risque fort de voir le délai s'allonger. Et pour ma part, je ne crois pas qu'il soit si difficile d'afficher de longues pages très rapidement : c'est une question de discipline, de logique et de rigueur dans sa manière de programmer, le tout associé à l'utilisation de outils qui sont mis à notre disposition, cache d'op-code, mise en cache des pages, indexation correcte des colonnes de la base de données, etc... les recettes ne manquent pas.

Donc en conclusion, tu n'es pas d'accord avec le propos d'Éric : soit, mais alors au lieu de lâcher un commentaire digne des sites de presse quotidienne où n'importe qui poste n'importe quoi, propose-nous une alternative, ou bien explique-nous pourquoi ce problème ne présenterait aucun intérêt.

Quant à l'article lui-même, il survole seulement le sujet global en évoquant quelques défauts de programmation souvent rencontrés : mais je reprends ce que je mentionnais un rien plus tôt, il faut être discipliné et ne pas oublier qu'on programme des machines qui ne feront que ce qu'on leur indique... ou non. Donc programmer proprement et avec logique est à mon sens une règle de base que devrait adopter n'importe quel développeur consciencieux.

28 décembre 2011, 13:05

gabriel :

Ca n'a pas plus de sens. Afficher une page de blog ou une page affichant le prix de l'essence en 20 ms, c'est bien bravo. Surtout quand l'essentiel du travail couteux est conservé en cache car peu soumis au changement. Ona va dire que le prix de l'essence ne change pas à la journée près, je peux me permettre de réinitialiser un cache, quelque que soit le niveau, à chaque modification. Maintenant, dans une application de stats sur 1 millions de lignes, produire un tableau de stats (beaucoup de calcul) en moins de 4 secondes, ca me parait très valable, surtout quand on ne peut rien mettre en cache. Après on peut toujours épiloguer sur combien de serveurs je vais rajouter pour "accélérer" mon temps d'affichage ... C'est très puérile d'arriver à un tel raisonnement sans connaitre le contexte de production de telle ou telle application. Ce qui me navre c'est que je vois fleurir de plus en plus de blog dont les auteurs racontent leur vie, démontrent à quel point ils sont formidable ... mais on tourne toujours en rond dans la diversité des sujets traités. Le premier qui m'explique comment accélérer une application avec du gpgpu, je lui payes une bière mais c'est loin d'arriver vu que la bonne grosse partie de la communauté visible php passe son temps à ergoter dans le vide et à se regarder le nombril. Alors oui c'est bien d'optimiser, on est le plus rapide, le plus fort, le plus ceci le plus cela ... mais au final, le client lui s'en fout. Lui ne voit que par ses propres critères qui sont loiiiiiiiiiiiiiiiiiiiiiiiiinnnnnn des critères d'appréciation du développeurs. Si a une seconde la page le client est content, mois je suis content. Voici ce que j'écrivais à un autre il y a peu :

Une solution n’est valable que pour un problème identifié dans un contexte donné. Si mon problème et/ou mon contexte change, ma solution doit être étudiée à nouveau, avec modification ou non. Ainsi, comme personne n’est devin, on ne peut avoir que l’intuition de l’avenir mais aucune certitude et comme il faut bien avancer, des décisions sont prises, non pas les meilleurs mais les moins pires, c'est-à-dire celle qui font un poids moyen entre coût, qualité et délai.

J’affirme que beaucoup de développeur devrait garder cela en tête et qu’il vaut mieux avoir une production moins dans les règles de l’art (comprendre quelque chose qui hérite du « beau ») et plus dans les délais et la qualité, plutôt qu’un clone de l’essence de la perfection où l’on se doit d’attendre n fois plus de temps. Toutefois, si j’obtiens le beure et l’argent du beurre je ne suis pas contre.

Je nomme cela « le bon sens allié à la réalité »

Ainsi, des biens pensants on introduit le concept de « refactoring », en réalité c’est juste un palliatif au remord, qui permet de revoir l’architecture d’un modèle afin de s’adapter au changement.

Bref, on ne produit jamais l’application ultime mais juste des instances qui tendent vers le mieux. D’ailleurs des petits malins ont créé des versions (sombre agencement de main, major et minor realease accouplé à des builds number et alpha, beta, gamma release …)

"Le bon sens allié à la réalité " m’indique que je ferai toujours des erreurs (je l’accepte) mais que tant que ma solution fonctionne c’est déjà çà de pris. Toutefois, cela ne doit servir de prétextes à tout et n’importe quoi. Il y a certaines bonnes pratiques à respecter issues de l’expérience (la mienne ou celle d’autres comme moi) qui s’imposent de fait lors que le nombre de développeurs augmente dans et autour de mon projet et qui, finalement, me permette de faire moins d’erreur.

Plus particulièrement sur ce papier : 1 - mettre des indexes dans une base de données, c'est une base très très scolaire ... maintenant il faut savoir pourquoi, dans quel but, pour quel effet, dans quelles conditions ... on peut aussi parler des index multicolonnes, sur une longueur d'une colonne (index sur des valeurs uniques c'est possible), on peut aussi parler des vues, des tables en mémoire

2 - utiliser un cache d'opcode : Je ne comprends pas pourquoi php n'est toujours pas compilé de base !! Ca pouvait se comprendre il y a 12 ans, du temps où les ide php étaient peu nombreux et avec peu de fonctionnalités De nos jours, on a des ide performants avec des outils de déploiements ... faire le fier avec son cache apc, c'est un non sens. C'est une juste une volonté de "zend la compagnie" de ne pas fournir un compilateur digne de ce nom afin de pouvoir placer ses produits (troll)

3 - Mettre en cache des parties de page ... ouais bon ok ca fait juste depuis phplib que ca se fait ...

Bon, désolé d'être aussi violent mais ca gave de lire ce genre de papier en ouvrant de bon matin planete php. C'est gonflant à force de voir toujours les mêmes redites depuis plus de 10 ans. C'est plein de bon sens ce que tu racontes mais venir se pavaner avec, ca n'apporte rien. Tout comme le papier que tu critiques. Si tu as de la ressource autant l'utiliser à introduire de nouvelles idées.

Sur ce bonne journée

28 décembre 2011, 13:29

Carine :

Certes le temps de calcul d'une page côté serveur est important, on ne dira jamais le contraire : c'est toujours mieux quand le code est optimisé, bien écrit, sans erreurs, etc. et quand l'architecture de la base de données est bien pensée, avec des index pertinents, etc.

Il me semble juste qu'il ne faudrait pas oublier qu'il n'y a pas que là-dessus qu'on peut agir. Le temps de calcul par le serveur est souvent largement inférieur au temps nécessaire au navigateur pour afficher effectivement la page. L'optimisation "frontend" aussi est importante (limiter le nombre de requête HTTP, réduire le poids des composants, ... ). Certaines optimisations peuvent être faites en PHP, en concaténant et en cachant les fichiers CSS et JS par exemple.

Sur un blog comme celui-ci, on ne gagnerait probablement pas grand-chose. Mais le principe reste valable.

28 décembre 2011, 13:45

Eric :

@Gabriel

Comme beaucoup de chose que je raconte ici, je me place dans le cadre d'un site web à destination du grand public. Et je pense que 4 secondes est un temps qui va faire fuir beaucoup de monde, même avec une contrainte de volumétrie de 1 million de lignes.

Ton client s'en fous peut être, mais tu as la chance de le connaître. Sur le web, mon "client" arrive sur un site et si ça met quatre seconde, il s'en va et ne reviendra plus jamais. Je n'ai pas moyen de lui expliqué que vu ma volumétrie, je ne peux pas faire autrement : je dois trouver une solution.

Moi aussi, cela m'a gonfler de voir un enième article présentant la micro-optimisation à la sauce print vs echo. Un débutant qui tomberais sur un billet de ce type penserais que echo vs print a de l'importance alors qu'il n'en a strictement aucune face au trois "méthodes" d'optimisation que je présente (qui sont tous sauf originale).

@Carine

Je suis d'accord, mais néanmoins, une fois les js et css chargé, le plus important reste le temps de calcul des pages afin que le site soit le plus dynamique possible. Je pense qu'un design "moyen" au niveau CSS et JS peut être pardonné par le client car il a tendance à attendre plus longtemps que la première page s'affiche (notamment à cause de la latence causé par le DNS).

28 décembre 2011, 14:57

Carine :

Je t'accorde qu'on ne peut pas tout rattraper et qu'il y aura forcément une latence causée par le DNS, ce n'est pas pour autant qu'on ne peut rien faire pour optimiser les performances d'affichage.

C'est un sujet très vaste, que la majorité des développeurs traite par le mépris, mais il n'en reste pas moins que quand un site met 4 secondes à s'afficher, il y a très très rarement 4 secondes de calcul sur le serveur.

Il suffit d'utiliser des outils comme webpagetest pour se rendre compte que ce temps de calcul représente souvent moins de 20% du temps nécessaire à l'affichage d'une page.

Je vais prendre un exemple. En testant aujourd'hui sur le site www.lemonde.fr, on voit bien qu'il met 11 secondes à tout charger la première fois et 6 secondes au second chargement. C'est encore un peu lent, mais ils ont fait de très sérieux progrès sur les performances web puisqu'avant il fallait plus de 30 secondes pour le premier chargement. Je le sais car c'est LE site que mes collègues "utilisaient comme référence pour illustrer leurs propos sur l'intérêt d'optimiser les performances web côté "frontend", car c'était un des sites les moins bien optimisés. Ce n'est pas en optimisant le code-source qu'ils ont pu gagner 20 secondes sur le temps de premier affichage. D'un point de vue retour sur investissement, je pense qu'ils ont bien fait de travailler sur les 29 secondes frontend plutôt que sur les 600/700ms côté backend. Non pas que leur code-source ne pourrait pas être optimisé, mais il y avait plus à gagner pour le visiteur à limiter le temps nécessaire à afficher la page.

28 décembre 2011, 15:22

Jérémy :

Le code PHP/MySQL n'est que la partie visible de l'iceberg. Le plus gros du chargement / latence d'un site se trouve malheureusement rarement de ce côté.

Ce site en est un excellent exemple : avec 10ms de calcul coté serveur, mon browser calcul un rendu en 200ms malgré des données déjà en cache (ce qui est à la fois remarquable comparé à d'autres blog, mais logique compte tenu de la charte graphique ultra épurée)

Le plus gros de l'iceberg se trouve sur la partie réseaux, c'est pourquoi il faut veiller à la taille des données qu'on envoie et qu'on reçoit.

Le plus gros gain de temps qu'on fait généralement sur les sites se trouve dans l'utilisation du cache du navigateur : - En spécifiant des date de validité des contenus statics -> supprime une requête et une réponse - En retournant des response 304 pour les contenus non modifiés -> supprime une réponse

Un autre gain se trouve dans le chargement des données : - Chargement asynchrone des données non indispensable (JS, Images) -> affichage de la page avant la fin du chargement - Parallélisation du télé-chargement des données en utilisant plusieurs sous-domaines (les navigateurs sont limité à 2 download consécutifs par domaine) -> supprime l'attente du téléchargement d'une image pour passer à la suivante - Allègement de la taille des requetes en supprimant les cookies pour les contenus static (en changeant de nom de domaines par ex) -> réduction de la taille des requêtes - Envois de requêtes via ajax plutôt que de recharger la page -> réduction de la taille des réponses

Ou encore dans le portage côté client de certains calculs pour éviter le re-chargement innutiles de pages : - Control de validation de formulaire (contrôle côté client ne dispense pas de ne pas en faire un autre côté serveur) -> Évite des requêtes / réponse inutiles dans le cas ou le formulaire est invalide.

28 décembre 2011, 18:37

mageekguy :

@gabriel : tout le monde ne se pavane pas et ne se regarde pas le nombril dans la communauté PHP. À la condition de sortir un peu des sentiers battus et de se donner la peine de chercher, il est possible de trouver des gens très compétents qui explore de nouvelles possibilités pour améliorer les performances des sites web. Certain se basent sur des solutions 100% PHP (c'est le cas du framework Hoa, par exemple), ou bien mixent plusieurs technologies dont PHP, à la manière de Loïc d'Anterroches par exemple, qui utilise python, PHP et Mongrel 2/ZeroMQ pour obtenir des choses proprement hallucinantes en terme de performances et qui sont utilisés au quotidien par des clients. Certes, ils ne programment pas de GPU, mais ils sont parfaitement capable de te coller un sacré mal de crâne et en conséquence, ta "généralisation" excessive me dérange. J'ajouterais que d'autres encore, à la manière de Jean-Marc Fontaine, milite pour la mise en place de bonnes pratiques répondant à la fois aux besoins de qualité des développeurs et du client. Et ces bonnes pratiques ne sont ni de la masturbations, ni du rêve : elles sont le fruit de l'expérience de différents experts vivant dans le monde réel qui utilisent différents langages et elles permettent d'obtenir des résultats concrets en terme de satisfaction client. D'autres encore, tel que moi, font un mélange de tout cela tout en essayant de faire bouger les lignes, de bousculer les habitudes et les légendes urbaines, via une communication un peu extrême dans la forme et la création d'outils plus simple et efficace tel que atoum. Alors non, PHP et sa communauté n'en sont pas resté à la PHPLib, paix ait son âme (ou pas, d'ailleurs, vu sa qualité plus que médiocre). Il faut juste savoir regarder au delà de la surface de l'eau. Ceci étant dit, je te rejoins sur un point : l'article ayant suscité la rédaction de ce billet ne méritait aucunement une telle publicité, que ce soit de la part de Nexen ou de ce blog : certaines choses ne valent pas le coup qu'on y réponde.

28 décembre 2011, 23:23

Pseudo :
URL :
Billet plus ancien : La première page HTML

Page générée par zenBlog