Accueil du site > SPIP > Mémoïzation

Mémoïzation

jeudi 29 octobre 2009, par Fil

Mémoïzation est un terme d’informatique, dont Wikipédia donne la définition suivante : « une technique consistant à réduire le temps d’exécution d’une fonction en mémorisant ses résultats d’une fois sur l’autre ». [1] C’est aussi le nom d’une nouvelle librairie de fonctions pour PHP, qui fait suite à mes expérimentations sur XCache.

Cette librairie est développée sous forme d’un plugin pour SPIP, mais est codée de manière autonome, ce qui permet de l’utiliser indépendamment de SPIP.

Sa double licence — LGPL ou MIT, selon votre choix — permet de l’intégrer librement dans n’importe quel projet PHP.

Il suffit d’inclure le fichier inc/memoization.php pour obtenir les fonctions suivantes :

mixed cache_me()
mixed cache_get(string key)
bool  cache_set(string key, mixed value [, int ttl])
bool  cache_isset(string key)
bool  cache_unset(string key)
int   cache_inc(string key [, int value [, int ttl] ])
int   cache_dec(string key [, int value [, int ttl] ])
bool  cache_lock(string key)
bool  cache_unlock(string key)

Ces fonctions sont assurées par le module xcache s’il est disponible, et dans le cas contraire par eaccelerator, APC, etc., voire même — au pire — par des méthodes utilisant le système de fichiers.

Ces fonctions sont très proches de ce que permet XCache. Comparé à XCache :
— on n’a pas conservé la fonction cache_unset_by_prefix, très difficile à émuler sur les autres librairies ;
— on a en revanche ajouté les fonctions cache_lock() et cache_unlock().

Interface de programmation (API)

mixed cache_me() est la fonction de mémoïzation proprement dite, telle que je l’ai décrite, sous le nom W(), dans un précédent article (« Utiliser xcache pour accélérer n’importe quel script PHP »).

Pour « mémoïzer » une fonction définie comme :

il suffit de lui ajouter une ligne :

Les résultats sont alors mémoïzés et restitués, lors de l’exécution de la même fonction par la suite (et avec les mêmes arguments), sans devoir refaire les calculs ; cela fonctionne bien sûr au sein d’un même hit, mais aussi entre des hits successifs consécutifs. (Pour les cas où il est judicieux d’employer cette technique, se reporter à l’article initial.)

 

Les autres fonctions de l’API sont plus traditionnelles :

mixed cache_get(string key) récupère la valeur stockée sous la clé $key, ou null si l’info n’est pas disponible ou a expiré.

bool cache_set(string key, mixed value [, int ttl]) stocke une valeur sous la clé $key, avec une durée d’expiration de ttl secondes (par défaut, pas d’expiration).
Renvoie true en cas de succès, false en cas d'échec.

bool cache_isset(string key) renvoie true si la clé a une valeur disponible et non expirée, false dans le cas contraire.

bool cache_unset(string key) efface l’éventuelle valeur de la clé key.

int cache_inc(string key [, int value [, int ttl] ]) ajoute value (par défaut, value=1) à la valeur numérique entière de la clé key, règle, le cas échéant, le ttl, et renvoie le résultat.

int cache_dec(string key [, int value [, int ttl] ]) retire value (par défaut, value=1) à la valeur numérique entière de la clé key, règle, le cas échéant, le ttl, et renvoie le résultat.

cache_lock(string key) verrouille la clé key, et assure l’unicité de notre accès à cette clé jusqu’à ce qu’on libère le lock, ou que le processus se termine.

cache_unlock(string key) déverrouille la clé key.

Notes

[1] Merci à Thomas Sutton d’avoir suggéré ce mot.

22 Messages de forum

  • Mémoïzation Le 29 octobre 2009 à 23:28 , par Fil

    À titre d’exemple voici comment je faisais, auparavant, pour mémoïzer le chargement d’une URL distante :

    function recuperer_page_cache($url, $delai=3600) {
       $cache = _DIR_CACHE.'url_'.md5($url);
       if (($GLOBALS['var_mode']
       OR !file_exists($cache)
       OR filemtime($cache)<time()-$delai
       )
       AND $contenu = recuperer_page($url))
           ecrire_fichier($cache, $contenu);
       lire_fichier($cache, $contenu);
       return $contenu;
    }

    désormais, je fais :

    function recuperer_page_cache($url, $delai=3600) {
       if (!is_null($W = cache_me(null, $delai)))
           return $W;
       return recuperer_page($url))
    }


    Non seulement c’est plus propre, mais le code tire automatiquement avantage d’un cache en RAM si celui-ci est dispo.

  • Mémoïzation Le 27 septembre 2010 à 00:11 , par Maïeul


    cela fonctionne bien sûr au sein d’un même hit, mais aussi entre des hits sucessifs.

    Tu m’avait parlé de le faire pour SPIP-Bible. Le truc c’est que la fonction "chronophage" (et energivore) de SPIP-Bible n’est pas appelé à chaque hit, mais que si quelqu’un va sur une page où la bible est citée (et oui !).

    Est ce alors pertinent ?

    • Mémoïzation Le 27 septembre 2010 à 00:19 , par Fil

      Oui, Bible ou pas, ce que je voulais dire c’est que les résultats qu’on stocke dans le cache peuvent être réutilisées plus tard, sur un autre hit — pas forcément celui qui suit immédiatement.

    • Mémoïzation Le 27 septembre 2010 à 00:22 , par Maïeul


      autre hit — pas forcément celui qui suit immédiatement.

      Alors il n’est pas successif :)

    • Mémoïzation Le 28 septembre 2010 à 23:44 , par Fil

      OK, va pour “consécutifs” alors.

  • Utilisable avec mem_cached et APC Le 30 novembre 2010 à 18:08 , par Sylvain

    Hello,

    Ce plugin fonctionne-t-il avec mem_cached et APC ?

    Merci,
    Sylvain

    • Utilisable avec mem_cached et APC Le 30 novembre 2010 à 18:13 , par Fil

      À l’heure actuelle le plugin Memoization pour SPIP fonctionne avec memcache, APC, xcache, et eaccelerator (sans compter l’option de base, filecache).

    • Utilisable avec mem_cached et APC Le 30 novembre 2010 à 19:12 , par Sylvain

      Ok, super et merci !

      Autres questions :
      - cela ne touche pas au fonctionnement habituel du cache de Spip sur la durée de mise en cache d’une page ou noisette ?
      - Cela ne fait que transférer le stockage du mécanisme de cache de Spip dans la RAM grâce à mem_cached ?

      Je viens de le tester et ça accélère bien le site : bravo et merci

    • Utilisable avec mem_cached et APC Le 2 décembre 2010 à 19:52 , par Fil

      Oui c’est exactement ça. La seule différence entre le cache SPIP classique et Memoization est dans le garbage collector ; avec Memoization il n’y en a tout simplement pas besoin (chaque système de cache gère son propre nettoyage des données périmées), ce qui permet d’éviter un bug récurrent sur les gros sites SPIP : l’« explosion » du cache.

  • Mémoïzation Le 3 décembre 2010 à 17:31

    Si je comprends bien, quand on utilise apc, il faut absolument la version 3.1.4 pour que ce soit possible de jouer avec ?

    Sous Lenny, on est toujours en version 3.0.19-2

  • Reverse_proxy de cache : Varnish Le 20 janvier 2011 à 13:32 , par Sylvain

    Hello,

    j’utilise sur mon hébergement un reverse_proxy de cache : Varnish. Je voudrais donc dédier la gestion du cache de Spip à ce reverse_proxy.

    Est-il prévu de gérer aussi Varnish ?

    Sinon, quels conseils pouvez-vous me donner pour l’implémenter svp ?
    Je vous ferai part des retours afin de l’intégrer au plugin memoization.

    Merci,
    Sylvain

    • Reverse_proxy de cache : Varnish Le 20 janvier 2011 à 13:39 , par Fil

      Désolé, je ne vois pas le rapport entre Varnish et le plugin de mémoization. (Et pourtant j’utilise aussi Varnish sur mon serveur !)

    • Reverse_proxy de cache : Varnish Le 24 janvier 2011 à 18:17 , par Sylvain

      Pour stocker le cache des pages entières HTML (pour les internautes non connectés) dans Varnish au lieu de le stocker dans un fichier Spip, servi par Apache+PHP.

      Mais il faut pouvoir communiquer avec Varnish pour lui dire de vider son cache :
      - entier quand on vide le cache
      - d’une url quand on clique sur recalculer cette page.

      Et le paramétrer pour qu’il prenne en compte le header x-spip-cache comme durée de vie d’une URL.

      Comment utilisez-vous Varnish avec Spip ?

    • Reverse_proxy de cache : Varnish Le 25 janvier 2011 à 11:55 , par Fil

      Ah, d’accord. Je fais une nette différence entre le cache interne de SPIP et le cache externe de Varnish.

      A mon sens il ne faut pas leur faire jouer le même rôle. Il me semble plus pertinent de faire des règles uniquement pour varnish, lui disant par exemple d’invalider tout son cache dès qu’il voit passer une URL de la forme var_mode=calcul.

      Mais rapidement on est confronté à deux problèmes :
      — les pages SPIP sont à priori "dynamiques", sauf si on indique dans le cache l’option #CACHE{...,cache-client}
      — les stats de SPIP sont basées sur le fait que le hit arrive jusqu’au PHP.

      Il faut donc résoudre ces deux questions avant de vouloir servir le contenu non statique via le cache de Varnish. Je te propose d’en discuter par email, et de voir si on peut constituer une doc à partir de ça.

  • Mémoïzation Le 1er février 2011 à 17:34 , par crowf00t

    Hello,

    J’ai activer le plugin sur mon site, et la taille du cache a explosé : genre 250mo pour un spip. Comment puis-je régler la taille du cache ?

    Je n’utilise ni apc, memcache ou xcache. J’ai laisser l’option par defaut : filecache. Les options du cfg sont :
    le mode de mémoization : Auto-Détection (filecache)
    Gérer le cache des pages : Par la mémoisation définie ci-dessus

    Merci bien

    • Mémoïzation Le 1er février 2011 à 21:41 , par Fil

      Pour l’instant, il n’y a pas de réglage limite pour le filecache ; le système prévoit une distribution homogène des caches parmi 16^4 fichiers. En modifiant cette valeur de 16^4 on doit pouvoir régler la taille maxi, mais il faut faire quelques essais.

    • Mémoïzation Le 15 février 2011 à 12:26 , par Beurt

      Ouah ! C’est vrai que ça monte vite les Mo... Je vais essayer de modifier le nombre de fichiers car j’arrive très vite à plus de 400Mo !

  • xcache Le 24 mai 2011 à 14:29 , par sasabouba

    Je suis tombé par hasard sur cet article et j’ai directement testé le plugin spip correspondant. Chez moi xcache (1.2.2) est activé mais malheureusement pas détecté par le plugin. Ennuyeux.

    • xcache Le 24 mai 2011 à 14:46 , par Fil

      il faut que PHP soit compilé avec la librairie xcache, pour qu’il puisse l’exploiter ; as-tu vérifié dans ton phpinfo() si c’est le cas ?

      • xcache Le 25 mai 2011 à 20:46 , par Loiseau2nuit

        Même problème ici en XCache 1.3.1,

        as-tu vérifié dans ton phpinfo() si c’est le cas ?

        c’est le cas !

        C’est grave Docteur ? :-O

    • xcache Le 25 mai 2011 à 21:24 , par Fil

      Plus précisément, pour que ça fonctionne il faut que la fonction xcache_set() soit disponible, et qu’elle fonctionne (à savoir, que XCache ait de la mémoire allouée pour les variables, et pas seulement pour les scrips compilés).

  • Mémoïzation Le 25 mai 2011 à 18:56

    ok merci je vais voir ça !