Mots-clé : optimisation

Python : f-string vs str()

Quelle est la différence de performance entre f"{x}" et str(x) ?

Voici mes tests qui m’ont surpris, car je m’attendais à l’inverse :

from typing import Dict

def benchmark() -> None:
  """Main
  function for benchmark.
  """
  t1 = timeit.timeit("f_str()",
                     globals=globals(),
                     number=50000000)
  t2 = timeit.timeit("u_str()",
                     globals=globals(),
                     number=50000000)
  t3 = timeit.timeit("n_str()",
                     globals=globals(),
                     number=50000000)
  d: Dict[str, float] = {
    "f-string": t1,
    "str": t2,
    "no str": t3
  }
  s: Dict[str, float] = {k: v
                         for k, v
                         in sorted(d.items(),
                                   key=lambda i:
                                   i[1])}
  f: float = min(s.values())
  print("Method\tTime\tPerc.")
  print("------\t----\t-----")
  for k, v in s.items():
    p: float = (v / f) * 100
    print(f"{k}\t{v:.2f}\t{p:.2f}%")

if __name__ == "__main__":
  import timeit
  class T:
    def __init__(
            self, l: str) -> None:
      self.l: str = l
  o: T = T("test")
  def f_str() -> str:
    return f"{o.l}"
  def u_str() -> str:
    return str(o.l)
  def n_str() -> str:
    return o.l
  benchmark()

Explications

  • f"{self.label}" utilise le mécanisme d’interpolation de chaînes de caractères de Python qui peut être légèrement plus rapide parce qu’il est optimisé pour concaténer des littéraux de chaîne et des variables ;
  • str(self.label) appelle explicitement le constructeur de la classe str, ce est un peu plus lent en raison de l’appel de fonction.

Symfony 2 : mon site de démonstration est sorti : livrepizzas

Mon site de démonstration pour l’utilisation du framework Symfony 2 est sorti.

http://www.livrepizzas.fr

Ce n’est qu’un site de démonstration, il est loin d’être parfait !

  • Bien sûr il est optimisé pour google et pour les mobiles et tablettes.
  • Bien sûr il est compatible w3c.
  • Bien sûr il est moderne et utilise du HTML5.
  • Bien sûr il est en responsive design.
  • Bien sûr c’est facile à faire. 🙂

Si vous avez des commentaires ou suggestions à faire, n’hésitez pas !

Cours optimisation Internet – Ecole d’ingénieurs des Mines

Après avoir fait ma présentation, cela fait toujours plaisir de savoir qu’on est suffisamment intéressé pour demander ma présentation !

Cliquez sur le lien pour la récupérer, et n’hésitez pas à laisser une appréciation sur ce qui était bien et ce qui manquait éventuellement, sachant que j’ai fait ce que je pouvais dans un laps de temps aussi court 😉

Cliquez ici.

Smarty 3.1 et les plugins : comment faire / howto

Sur la toute dernière version de Smarty (3.1), voici comment créer un plugin personnalisé.
Pour résumer, l’un de mes sites n’était pas assez optimisé.
Le code qui sortait était :

<body class="sbody">
    <div>
....
    </div>
....
</body>

J’ai donc ajouté le filtre d’optimisation qui supprime les espaces en début :

$this->smarty->loadFilter('output', 'trimwhitespace');

Le code de sortie est devenu :

<body class="sbody"><img src="/title.jpg" /><div>....</div>....</body>

Tout mise en une ligne, super !
Le seul problème, c’est que ça ne fonctionnait pas avec le code JavaScript, il faut en effet les retours à la ligne.
J’ai donc crée mon plugin qui ne fait que supprimer les espaces en début de ligne, et remplacer de « retour + line feed » (deux octets) de fin de ligne par un seul octet « retour ».

Voici le code, je vous laisse comprendre, c’est extrêmement simple :

/* Déclarer un plugin "block".
 * Block = il faut un début et une fin.
 * Ici : {triml} {/triml}
 */
$this->smarty->registerPlugin('block',
  'triml', array($this,'smarty_block_trim_l'));

Après avoir déclaré le plugin, il faut faire la fonction adéquate :

/**
 * Fonction de plugin smarty pour supprimer tous les espaces
 * en début de ligne entre les blocs {triml}{/triml}
 * "triml" = trimleft
 * Voir le constructeur et chercher $this->smarty->registerPlugin()
 *
 * @param array $params les paramètres qu'on passe à {strip_nl}
 * @param variant $content Le contenu qu'il y a dans le bloc
 * @param variant $template Le nom du template
 * @param variant &$repeat
 *
 * @return int Description retour
 */
public function smarty_block_trim_l(
  array $params, $content, $template, &$repeat)
{
  $content = preg_replace('/\n[\s]+/', "\n", $content);
  return $content;
}

Et voilà maintenant, vous pourrez aussi optimiser votre site comme un professionnel.
Bien évidemment le gain le plus gros est dans la compression (voir mod_deflate)

Php / optimisation / compilation et le projet du compilateur FaceBook

Saviez vous que Facebook a eu une idée assez intéressante ?
Ils ont crée un outil qui transforme le code Php en code C++ et qu’on peut donc compiler.
D’ailleurs la plupart des choses de FaceBook tournent via cet outil, pour accélérer et optimiser au maximum leur site.
Il est ainsi possible de pousser la performance Php à l’extrême.

Pour ceux qui veulent rendre leur site encore plus rapide, voici le lien :

https://github.com/facebook/hiphop-php

UglifyJS : meilleur et plus rapide que Google Closure Compiler et YUI

Merci à Mathieu Robin, ici, pour les petites explications de jQuery 1.5, dans lequel on peut lire qu’ils ont laissé tomber Google Closure Compiler pour UglifyJS.

UglifyJS est une librairie de compression/optimisation de code JavaScript. Dit autrement, vous écrivez votre code en JavaScript, vous le testez, avec les commentaires et tout et tout, et puis dès que vous pensez qu’il est prêt, hop, vous le passez à la moulinette UglifyJS et vous aurez un code super compressé, sans aucun commentaire, mais qui fonctionnera à l’identique de l’original, et vous pourrez le mettre sur votre serveur de production.

PS : Si si il est bien 2:44 du matin, j’ai fini de donner le bib’ à mon fils (^_^)

Php : optimisation vs lisibilité

Attention, ce qui suit ne s’applique pas systématiquement partout, mais il faut avoir cela en tête dans certaines occasions.

Ci-suivent deux possibilités de codes qui font exactement la même chose : vous allez certainement me dire : le code 2 est très nettement moins bien que le code 1, à savoir que si on veut rajouter quelque chose dans le 1 c’est une ligne alors que dans le 2 c’est quatre lignes. Eh bien c’est vrai, mais il faut garder le code 2 qui est plus long et qui semble se répéter de manière inutile. Pourquoi, me demanderez-vous ? Je vais vous dire pourquoi :

Il faut toujours adapter le code en fonction de votre supérieur hiérarchique.

Si, si, je ne plaisante pas. Si vous avec un patron qui vous dit, une bonne fois pour toutes : « Voilà les champs qu’on utilisera cela ne changera pas », et, surtout, que c’est vrai, alors vous pouvez vous faire plaisir et factoriser au maximum. A l’inverse, un patron qui arrive et qui vous dit « Voilà les champs qu’on utilisera cela ne changera pas », et, le connaissant vous savez que c’est faux, alors utilisez le code 2. Cela m’arrive tout le temps : « Au fait Olivier j’ai oublié de te dire : il y a un nouveau champ garantie qui est, en réalité un pourcentage d’une autre garantie et il faut s’assurer que l’autre existe vraiment ». Si vous avez adopté le code 1 avec ce genre de patron, vous êtes fichu : Ce code n’est pas prévu pour gérer des exceptions.

Dernier argument pour le code 2 : il est beaucoup plus compréhensible que le code 1. Beaucoup, beaucoup, beaucoup. Et si quelqu’un doit prendre le relai après vous, votre objectif en tant que professionnel, c’est de lui faciliter la tâche au maximum. Donc… vive le code 2 !

Code 1

private function CreerTableauValeursGarantie($gar,$tab)
{
 foreach ($tab as $fc_aff=>$tab_get) {
  if ($gar->$fc_aff()) {
   foreach ($tab_get as $idx=>$fc_get) {
    $ret[$idx]=$gar->$fc_get();
   }
  }
 }
}


$tab_gar[$id_g][$idp_idf] =
 $this->CreerTableauValeursGarantie($gar, array(
  'getAffSurmortalite' => array(
   VAL_SURMORTALITE => 'getTauxSurprime2'),
  'getAffSurprime1' => array(
   VAL_SURPRIME_ADDITIONNELLE_DUREE_1 => 'getSurprimeAddDuree1',
   VAL_SURPRIME_ADDITIONNELLE_TAUX_1 => 'getSurprimeAddTaux1'),
  'getAffSurprime2' => array(
   VAL_SURPRIME_ADDITIONNELLE_DUREE_2 => 'getSurprimeAddDuree2',
   VAL_SURPRIME_ADDITIONNELLE_TAUX_2 => 'getSurprimeAddTaux2'),
  'getAffSurprime3' => array(
   VAL_SURPRIME_ADDITIONNELLE_DUREE_3 => 'getSurprimeAddDuree3',
   VAL_SURPRIME_ADDITIONNELLE_TAUX_3 => 'getSurprimeAddTaux3'),
  'getAffSurprime4' => array(
   VAL_SURPRIME_ADDITIONNELLE_DUREE_4 => 'getSurprimeAddDuree4',
   VAL_SURPRIME_ADDITIONNELLE_TAUX_4 => 'getSurprimeAddTaux4'),
  'getAffSurprime5' => array(
   VAL_SURPRIME_ADDITIONNELLE_DUREE_5 => 'getSurprimeAddDuree5',
   VAL_SURPRIME_ADDITIONNELLE_TAUX_5 => 'getSurprimeAddTaux5'),
  'getAffExclusionsPathos' => array(
   VAL_GAR_EXCLUSIONSPATHOS => 'getExclusionsPathologies' ),
  'getAffExclusionsSports' => array(
   VAL_GAR_EXCLUSIONSSPORTS => 'getExclusionsSports' ),
  'getAffExclusionsProfs' => array(
   VAL_GAR_EXCLUSIONSPROFS => 'getExclusionsProfessions' ),
  'getAffMensualite' => array(
   VAL_GAR_MENSUALITE => 'getMensualite' ),
  'getAffFranchise' => array(
   VAL_GAR_FRANCHISE => 'getAffFranchise' )));

Code 2


if ($gar->getAffSurmortalite()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURMORTALITE ] =
  $gar->getTauxSurprime2();
}
if ($gar->getAffSurprime1()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_DUREE_1 ] =
  $gar->getSurprimeAddDuree1();
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_TAUX_1 ] =
  $gar->getSurprimeAddTaux1();
}
if ($gar->getAffSurprime2()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_DUREE_2 ] =
  $gar->getSurprimeAddDuree2();
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_TAUX_2 ] =
  $gar->getSurprimeAddTaux2();
}
if ($gar->getAffSurprime3()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_DUREE_3 ] =
  $gar->getSurprimeAddDuree3();
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_TAUX_3 ] =
  $gar->getSurprimeAddTaux3();
}
if ($gar->getAffSurprime4()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_DUREE_4 ] =
  $gar->getSurprimeAddDuree4();
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_TAUX_4 ] =
  $gar->getSurprimeAddTaux4();
}
if ($gar->getAffSurprime5()) {
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_DUREE_5 ] =
  $gar->getSurprimeAddDuree5();
 $tab_gar[$id_g][$idp_idf][VAL_SURPRIME_ADDITIONNELLE_TAUX_5 ] =
  $gar->getSurprimeAddTaux5();
}
if ($gar->getAffExclusionsPathos()) {
 $tab_gar[$id_g][$idp_idf][VAL_GAR_EXCLUSIONSPATHOS ] =
  $gar_cm->getExclusionsPathologies();
}
if ($gar->getAffExclusionsSports()) {
 $tab_gar[$id_g][$idp_idf][VAL_GAR_EXCLUSIONSSPORTS ] =
  $gar_cm->getExclusionsSports();
}
if ($gar->getAffExclusionsProfs()) {
 $tab_gar[$id_g][$idp_idf][VAL_GAR_EXCLUSIONSPROFS ] =
  $gar_cm->getExclusionsProfessions();
}
if ($gar->getAffMensualite()) {
 $tab_gar[$id_g][$idp_idf][VAL_GAR_MENSUALITE ] =
  $gar_cm->getMensualite();
}
if ($gar->getAffFranchise()) {
 $tab_gar[$id_g][$idp_idf][VAL_GAR_FRANCHISE ] =
  $gar_cm->getAffFranchise();
}

MySQL : optimisation MySQL : sur le "order by"

Voilà une manière efficace d’accélérer de manière hallucinante les requêtes qui ont, dans le résultat explain, un extra qui est : USING filesort. Cet extra ralenti énormément la requête.

La solution est très simple : les colonnes de la clause ORDER BY doivent se retrouver dans le WHERE : voilà, dans l’exemple qui suit, col1 et col3 qui sont des indexes. S’ils n’apparaissent pas des deux côtés, alors, il y a l’horrible USING filesort :


mysql> EXPLAIN SELECT * FROM testtab
WHERE col1 > 50000 AND col1 < 150000 ORDER BY col3;
Extra: USING WHERE; USING filesort
mysql> EXPLAIN SELECT * FROM testtab
WHERE col1 > 50000 AND col3 < 20000 ORDER BY col3;
Extra: USING WHERE
mysql> EXPLAIN SELECT * FROM testtab
WHERE col3 < 20000 AND col1 > 50000 ORDER BY col3;
Extra: USING WHERE
mysql> EXPLAIN SELECT * FROM testtab WHERE col3 < 20000
ORDER BY col3;
Extra: USING WHERE
mysql> EXPLAIN SELECT * FROM testtab WHERE col3 < 20000
ORDER BY col1;
Extra: USING WHERE; USING filesort
mysql> EXPLAIN SELECT * FROM testtab WHERE col1 < 20000
ORDER BY col1;
Extra: USING WHERE
mysql> EXPLAIN SELECT * FROM testtab WHERE col1 < 20000
ORDER BY col3;
Extra: USING WHERE; USING filesort