Accueil du site > SPIP > Utiliser xcache pour accélérer n’importe quel script PHP

Utiliser xcache pour accélérer n’importe quel script PHP

samedi 11 avril 2009, par Fil

Un cache PHP comme xcache permet de stocker en RAM n’importe quelle donnée, pour la retrouver par la suite. Voici un script permettant d’exploiter ce système pour mémoriser et récupérer le résultat d’une fonction dont le calcul, lourd, serait fait de manière répétée.

//
// Cache function W()
// (c) Fil 2009 - Double-licensed under the GNU/LGPL and MIT licenses
// http://zzz.rezo.net/-SPIP-
// $ttl = time to live
// $vars = other variables that could change the result
// (the function's variables are automatically taken into account)
//
# xcache ?
if (function_exists('xcache_set')) {
        function W($vars=null, $ttl=3600) {
                $trace = debug_backtrace();
                $trace = $trace[1];
                $key = __FILE__ . md5(
                        $trace['function']
                        .serialize($trace['args'])
                        .serialize($vars)
                );
                if (!xcache_isset($key)) {
                        xcache_set($key, null, $ttl);
                        $r = call_user_func_array($trace['function'], $trace['args']);
                        xcache_set($key, $r, $ttl);
                        return $r;
                }
                return xcache_get($key);
        }
}
# elementary compatibility
else {
        function W(){return null;}
}

Pour exploiter ce script dans n’importe quelle fonction PHP, il suffit d’ajouter au début de la fonction une très courte ligne de code :

if (null!==$W=W())return$W;

Par exemple, la fonction suivante, qui prend 3 secondes à calculer :

function calcul_lourd($x, $y) {
        sleep(3);
        return sqrt($x*$y);
}

peut être mise en cache très simplement :

function calcul_lourd($x, $y) {
        if(null!==$W=W())return$W;
        sleep(3);
        return sqrt($x*$y);
}

Le calcul ne prendra 3 secondes que la première fois, les hits suivants ne prenant qu’environ 0,00001 seconde.

Quand ne pas l’utiliser

Bien entendu toutes les fonctions ne doivent pas être optimisées de cette manière. Exemples de fonctions à ne pas traiter :
- une fonction peut faire des choses (écrire une donnée dans une base de données...), produire du contenu à l’écran (print ...), ou encore donner un résultat changeant (selon l’heure, ou le hasard). Dans ce cas, on ne peut pas utiliser cette méthode sur la fonction en question ;
- une fonction peut être suffisamment rapide pour que le gain apporté ne compense pas le surcoût engendré par le script, qui est d’environ 10 microsecondes ;
- si une fonction est appelée avec des paramètres qui changent à chaque fois, il est inutile de stocker son résultat !

Bref, il s’agit de repérer les fonctions qui méritent d’être optimisées : celles prennent un peu de temps à calculer (plus de 10 microsecondes), qui voient passer les mêmes arguments de façon répétée, et qui ne produisent pas d’action ni d’affichage. Enfin, faire attention à ne pas sur-optimiser : si une fonction A appelle une fonction B, il n’est pas nécessaire d’optimiser A si le gros du calcul se fait à l’intérieur de B.

Paramètres supplémentaires

Dans le cas où le résultat de la fonction à optimiser dépend de paramètres qui ne figurent pas dans ses arguments (par exemple de variables globales), il faut l’indiquer au script :

        if(null!==$W=W($parametres))return$W;

Par exemple pour optimiser la fonction suivante :

function bonjour_vous() {
  if (isset($_SESSION['auteur'])) {
     mysql_query();
     .../...
     return 'Bonjour '.$nom;
  }
  return 'Bonjour anonyme';
}

on appellera :

function bonjour_vous() {
  if(null!==$W=W($_SESSION['auteur']))return$W;
  if (isset($_SESSION['auteur'])) {
     mysql_query();
     .../...
     return 'Bonjour '.$nom;
  }
  return 'Bonjour anonyme';
}

Dans cette écriture $parametres peut être n’importe quel type de variable : nombre, chaîne de caractères, tableau...

Durée de vie du cache

Par défaut la durée de vie du cache ($ttl) est de 3600 secondes. On peut préciser une valeur différente en second argument de la fonction W(). Par exemple pour indiquer un TTL de 30 secondes :

  if(null!==$W=W(null,30))return$W;

Crédits

Ce script écrit par mézigue est distribué sous la double licence GNU/LPGL et MIT. Vous pouvez donc l’utiliser, grosso modo, comme bon vous semble, à condition de conserver ma signature. Les suggestions d’améliorations sont les bienvenues !

Distribution

Le script peut être utilisé tel quel dans vos projets PHP.

Il est aussi distribué en plugin pour SPIP, à télécharger :
- SVN : svn://zone.spip.org/spip-zone/_plugins_/xcache/
- ZIP : http://files.spip.org/spip-zone/xcache.zip

7 Messages de forum

  • Utiliser xcache pour accélérer n’importe quel script PHP Le 28 mai 2009 à 11:23 , par Rebekos

    Bonjour,

    j’ai pas bien compris le but de la manipulation.
    Cherche ton a garder en cache
    I. le resultat du calcule de la fonction
    OU BIEN
    II. la Fonction elle-meme, c’est a dire le temps de son `interpretation ` par apache ?
    Dans ce cas la fonction serait comme `precompilé` comme une fonction native de php.

    Evidement le cache fonctionnerait et serait disponible lors du changement de pages.

    Mais quand serait liberes la memoir Ram du server ?

    Merci

    • Les deux. XCache sert de cache opcaode (il cache la version compilée de la fonction). Mais avec ce script c’est bien le résultat du calcul qu’on garde en RAM d’un hit sur l’autre. Quand on en a trop stocké, XCache s’occupe de gérer sa mémoire en libérant les trucs mémorisés qu’il ne peut pas conserver.

  • Utiliser xcache pour accélérer n’importe quel script PHP Le 29 mai 2009 à 10:16 , par squirrel :D

    « Ce script écrit par mézigue est distribué sous la double licence GNU/LPGL et MIT. Vous pouvez donc l’utiliser, grosso modo, comme bon vous semble, à condition de conserver ma signature. Les suggestions d’améliorations sont les bienvenues ! »

    Vraiment intéressant mais ou est le script >_ !?!_<

    squirrel :D

  • Utiliser xcache pour accélérer n’importe quel script PHP Le 29 mai 2009 à 10:19 , par squirrel :D

    Le script serait juste c’est quelques lignes de code !! Cool !

    //
    // Cache function W()
    // (c) Fil 2009 - Double-licensed under the GNU/LGPL and MIT licenses
    // http://zzz.rezo.net/-W-
    // $ttl = time to live
    // $vars = other variables that could change the result
    // (the function's variables are automatically taken into account)
    //
    # xcache ?
    if (function_exists('xcache_set')) {
           function W($vars=null, $ttl=3600) {
                   $trace = debug_backtrace();
                   $trace = $trace[1];
                   $key = __FILE__ . md5(
                           $trace['function']
                           .serialize($trace['args'])
                           .serialize($vars)
                   );
                   if (!xcache_isset($key)) {
                           xcache_set($key, null, $ttl);
                           $r = call_user_func_array($trace['function'], $trace['args']);
                           xcache_set($key, $r, $ttl);
                           return $r;
                   }
                   return xcache_get($key);
           }
    }
    # elementary compatibility
    else {
           function W(){return null;}
    }
  • Utiliser xcache pour accélérer n’importe quel script PHP Le 30 août 2010 à 16:27 , par squirrel

    Çà peu peut être servir !

    http://code.google.com/p/brutis/

    Squirrel :-)

  • Utiliser xcache pour accélérer n’importe quel script PHP Le 4 janvier 2011 à 12:38 , par Jean-Pierre LOMBARD

    Bonjour,
    Je cherche évidemment à accélérer Webtrees car en l’état on ne peut pas s’en servir car beaucoup trop long. Ce script, j’aimerais bien m’en servir mais n’étant pas "programmeur émérite" comme vous, si vous me dites dans quel fichier et à quelle place je dois le copier-coller, si je dois rebooter,etc... vous risquez de me rendre un fier service effectivement et c’est -j’ai cru comprendre- votre but : soyez-en remercié d’avance.

    Merci de votre réponse

    • Il faut chercher dans ce script les fonctions qui ont les caractéristiques que j’indique dans l’article : lourdes et appelées répétitivement avec les mêmes arguments. Ensuite il suffit de copier/coller la fonction W() et de l’appeler dans les fonctions en question.