Memoization, la librairie

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 ». C’est aussi le nom d’une nouvelle librairie de fonctions pour PHP, qui fait suite à mes expérimentations sur XCache.
À l’heure actuelle le plugin Memoization pour SPIP fonctionne avec memcache, APC, xcache, eaccelerator et redis, ainsi que sur l’option de base, filecache.

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. C’est cet aspect qui est détaillé dans cet article. Pour la doc du plugin, voyez l’article « Plugin mémoization ».

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

Le fichier memoization_options.php définit 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)
mixed cache_edito_get($key)
mixed cache_edito_set($key, $value)

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().

Les fonctions cache_edito_get et cache_edito_set complètent ce jeu de fonction : lorsqu’une valeur a été mise en cache par cache_edito_set , on ne la récupère avec cache_edito_get que si le cache SPIP n’a pas été invalidé depuis, par une modification du contenu éditorial.

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 autre article (« Utiliser xcache pour accélérer n’importe quel script PHP »).

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

function A($param) {
	calculs ...
	return $resultat;
}

il suffit de lui ajouter une ligne :

function A($param) {
	if (!is_null($W = cache_me())) return $W;
	calculs ...
	return $resultat;
}

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.)

Exemple

À 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.

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.

Discussion

No discussion

Add a comment

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite / PostgreSQL
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparait.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Who are you?
[Log in]

To show your avatar with your message, register it first on gravatar.com (free et painless) and don’t forget to indicate your Email addresse here.

Enter your comment here

This form accepts SPIP shortcuts {{bold}} {italic} -*list [text->url] <quote> <code> and HTML code <q> <del> <ins>. To create paragraphs, just leave empty lines.

Add a document

Follow the comments: RSS 2.0 | Atom