JeuWeb - Crée ton jeu par navigateur
Choix du stockage des variables et du cache - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Choix du stockage des variables et du cache (/showthread.php?tid=3560)

Pages : 1 2


Choix du stockage des variables et du cache - Argorate - 17-03-2014

Bonjour,

je voulais qu'on discute ensemble d'un sujet sur lequel je travail en ce moment, à savoir la gestion du cache pour des données globale au jeu, exemple: j'ai un tableau qui contient la liste des couts de chaque action du jeu.

Donc j'ai tester les différents moyens de stocker et de récupérer ces données et nottament au niveau des cache : APC, memcache et memcached.

Je partage ici les résultats, on pourra discuter des conclusions et si quelqu'un a mieux à proposer...

Note 1: les temps ici ne sont pas divisé par le nombre de boucle, il s'agit juste du cumule du temps, sauf pour les tests de temps d'inclusion de fichier ou de connexion au serveur memcache qui eux sont divisé par le nb de boucle (puisqu'il n'y a généralement qu'une connexion nécessaire)

Note 2: les méthodes 1 et 2 ont été réalisé avec la mise en cache de l'opcode avec APC.

Note 3: il s'agit de résultat obtenu non pas en local mais avec mon serveur en ligne où Dévotion est héberger.

Note 4: certains tests sont dans des while différents pour limité les effets de bords (après plusieurs tests, je me suis rendu compte que si je met tout dans la même boucle, certains résultat sont ralenti...)

Note 5: il s'agit de résultat obtenu non pas en local mais avec mon serveur en ligne où Dévotion est héberger.


CODE utilisé pour le test:


$timer['timer_global'] = microtime(true);

require_once 'data.php';
require_once 'data_class.php';

$memcached = new Memcached();
$memcached->addServer('localhost', 11211);

$mc = new Memcache();
$mc->addServer('localhost', 11211);

$i=0;
$timer['nb'] = 100000;
while($i<$timer['nb'])
{
$t = microtime(true);
$GLOBALS['test_data_file']['titi'];
$timer['globals_var'] += microtime(true) - $t;

$t = microtime(true);
Toto::$data['titi'];
$timer['static_var_in_class'] += microtime(true) - $t;

$i++;
}

$i=0;
while($i<$timer['nb'])
{
$t = microtime(true);
apc_store('test_de_perf_apc', ['toto', 42]);
$timer['apc']['set'] += microtime(true) - $t;

$t = microtime(true);
apc_fetch('test_de_perf_apc');
$timer['apc']['get'] += microtime(true) - $t;


$t = microtime(true);
$memcached->set('test_de_perf_mem', ['toto', 42]);
$timer['memcached']['set'] += microtime(true) - $t;

$t = microtime(true);
$memcached->get('test_de_perf_mem');
$timer['memcached']['get'] += microtime(true) - $t;

$t = microtime(true);
$mc->set('test_de_perf_mem2', ['toto', 42]);
$timer['memcache']['set'] += microtime(true) - $t;

$t = microtime(true);
$mc->get('test_de_perf_mem2');
$timer['memcache']['get'] += microtime(true) - $t;

$i++;
}

$i=0;
while($i<$timer['nb'])
{
$t = microtime(true);
$memcached = new Memcached();
$memcached->addServer('localhost', 11211);
$timer['memcached']['connect'] += microtime(true) - $t;

$t = microtime(true);
$mc = new Memcache();
$mc->addServer('localhost', 11211);
$timer['memcache']['connect'] += microtime(true) - $t;


$t = microtime(true);
require 'test_include.php';
$timer['require_file'] += microtime(true) - $t;

$t = microtime(true);
include 'test_include.php';
$timer['include_file'] += microtime(true) - $t;

$i++;
}

$timer['include_file'] = floatalize($timer['include_file']/$timer['nb']);
$timer['require_file'] = floatalize($timer['require_file']/$timer['nb']);
$timer['memcached']['connect'] = floatalize($timer['memcached']['connect']/$timer['nb']);
$timer['memcache']['connect'] = floatalize($timer['memcache']['connect']/$timer['nb']);

$timer['timer_global'] = microtime(true) - $timer['timer_global'];
var_dump($timer);

avec data.php :
<?php
$GLOBALS['test_data_file'] = ['titi' => 42, 'tralala' => 2];
et avec data_class.php :
<?php
class Toto
{
static $data = ['titi' => 42, 'tralala' => 2];
}

test_include.php étant un fichier vide.

j'utilise PHP 5.4 (d'où l'absance de "array()")
function floatalize() => http://www.jeuweb.org/showthread.php?tid=7495&pid=95650#pid95650

Résultats :
Code :
array(9) {
  ["timer_global"]=>
  float(132.59713315964)
  ["nb"]=>
  int(100000)
  ["globals_var"]=>
  float(0.141921043396)
  ["static_var_in_class"]=>
  float(0.1264328956604)
  ["apc"]=>
  array(2) {
    ["set"]=>
    float(1.3067555427551)
    ["get"]=>
    float(0.51916360855103)
  }
  ["memcached"]=>
  array(3) {
    ["set"]=>
    float(13.609169960022)
    ["get"]=>
    float(11.365718603134)
    ["connect"]=>
    string(19) "0.00060304543018341"
  }
  ["memcache"]=>
  array(3) {
    ["set"]=>
    float(15.925793886185)
    ["get"]=>
    float(14.207545518875)
    ["connect"]=>
    string(20) "0.000079657964706421"
  }
  ["require_file"]=>
  string(20) "0.000026363780498505"
  ["include_file"]=>
  string(20) "0.000010960853099823"
}

Conclusions:

Postulat: la mise en cache ne se fait qu'une fois et n'est actualise que rarement lors de mise à jours.
Donc ce qui importe ce n'est pas le "set" met le fait de "get" une variable.

Résumé des résultats dans l'ordre:
Citation ://méthode #2
["static_var_in_class"]=> 0.1264328956604


//méthode #1
["globals_var"]=> 0.141921043396


//méthode #5
["apc"]=> 0.51916360855103

//méthode #3
["memcached"]=> 11.365718603134

//méthode #4
["memcache"]=> 14.207545518875


Il y a donc environ un facteur 100 entre la variable static et memcache !

On remarque également que l'inclusion d'un fichier (dont l'opcode est caché) est plus rapide (0.000010960853099823), lui meme plus rapide que le require (0.000026363780498505) que la connexion au serveur de memcached (0.00060304543018341) mais pas de memcache (0.000079657964706421).

Il faut aussi savoir que memcache à la différence d'APC est taillé pour une archi distribué (quand votre infrastructure est dispatché entre plusieurs serveurs), là où APC semble atteindre sa limite.


RE: Choix du stockage des variables et du cache - niahoo - 17-03-2014

hello, interessant, mais que veux tu montrer avec la variable static ?


RE: Choix du stockage des variables et du cache - Argorate - 17-03-2014

En fait, actuelement j'utilise le cache utilisateur d'APC pour stocker les données static de mon jeu. Et j'ai des soucis (le cache se vide tout seul malgrès différent essai de conf), donc je voulais tester memcache puisqu'on m'en a dit que du bien.

Mais en faisant ces tests je me suis rendu compte que c'était pas le plus rapide.

Je vais donc crée des classes pour gérer mes données static que je mettrais en variable static, c'est ce qui semble le plus optimisé.

Exemple:

class Data
{
static $cout_action = [ ... ]
}

là où pour l'instant j'ai un truc du genre:


function data($data_name)
{
if(empty($GLOBALS['DATA_CACHE'][$data_name]))
$GLOBALS['DATA_CACHE'][$data_name] = apc_fetch($data_name);
return $GLOBALS['DATA_CACHE'][$data_name];
}

avec un script qui load les variables dans APC.


C'est juste une façon de faire, je cherchais la meilleur, je fais paratager mes tests voilà tout ^^


RE: Choix du stockage des variables et du cache - Ter Rowan - 17-03-2014

(17-03-2014, 09:33 AM)niahoo a écrit : hello, interessant, mais que veux tu montrer avec la variable static ?

pareil

il faudrait savoir la quantité de données que tu cherches à manipuler (10 lignes, 100000 lignes, pas pareil.

De plus la comparaison entre variable et un système de cache n'est vraiment pertinente que s'il y a plusieurs connexions en simultané je pense.

A noter : tu introduis le biais de l'opération $timer['XXX'] += microtime(true) - $t dans tes cacluls

tu ferais mieux d'initialiser $t avant la boucle, faire la boucle avec les opérations, et calculer $timer['XXX'] une seule fois après la boucle. Ca te donnera peut être des résultats plus marquants encore.


RE: Choix du stockage des variables et du cache - niahoo - 17-03-2014

tu es conscient que les variables static ne sont pas partagées entre les différentes requêtes qui lancent PHP ?


RE: Choix du stockage des variables et du cache - Arnadus - 17-03-2014

(17-03-2014, 11:45 AM)niahoo a écrit : tu es conscient que les variables static ne sont pas partagées entre les différentes requêtes qui lancent PHP ?

+1


RE: Choix du stockage des variables et du cache - Ter Rowan - 17-03-2014

(17-03-2014, 11:45 AM)niahoo a écrit : tu es conscient que les variables static ne sont pas partagées entre les différentes requêtes qui lancent PHP ?

si c'est pour moi la question, oui, justement c'est pour cela que je dis que la comparaison "performance" ne peut s'évaluer que s'il y a plusieurs connexions. Dans le cas contraire, en test unitaire, l'inclusion d'un fichier sera probablement toujours plus rapide qu'un système de cache


RE: Choix du stockage des variables et du cache - niahoo - 17-03-2014

Non, la question est pour Argorate. Mais à te lire, on dirait que tu fais la même confusion :

Il n'y a rien à comparer. On ne peut pas stocker d'informations dans des variables statiques et espérer que les requêtes successives ou concurrentes verront les variables statiques avec cette nouvelle information. Ce ne sera pas le cas.

En relisant son post, si "avec un script qui load les variables dans APC" s'applique aux variables statiques alors OK. Mais du coup ça veut dire charger toutes les variables du cache concernées au chargement d'une classe au lieu de charger uniquement les données au besoin ... pas sûr que ça accélère quoi-que ce soit.


RE: Choix du stockage des variables et du cache - Argorate - 17-03-2014

Si c'est partager dans le sens où c'est identique. Il s'agit de stocker les données static du jeu (exemple: le cout d'un dépalcement sur un terrain), à l'inverse des données dynamiques (exemple : le type de terrain d'une case, qui lui doit etre en bdd).

C'est au programmeur de créer les variables static et d'inclure les classes qu'au besoin pour pas avoir à load toutes les données static du jeu à chaque fois, mais uniquement celle dont on a besoin, suffit juste d'adapter la fonction data() avec le bon include, avec une convention de nommage des fichiers et des variables qui soit identique.

Le nombre de connexion n'a pas d'influance dans le sens où y a rien de concurentiel là dedans:
Data_cout_action::$data['attaquer'] = 42; ça restera tjs à cette valeur, pour tous, et peut importe le nb de requetes.

Après c'est possible qu'un memcache soit encore plus lent si y a plusieurs mecs qui demmande l'accès à la meme variable en même temps?! Raison de plus en tout cas pour mettre ça en static du coup...^^


RE: Choix du stockage des variables et du cache - niahoo - 17-03-2014

Hum si en début de code tu fais
Code :
Data_cout_action::$data['attaquer'] = 42;

Pourquoi ne pas utiliser une constante ?

Code :
class Data_cout_action {
    const attaquer = 42;
}

C'est ça que je ne comprend pas, pourquoi mélanger ça avec les systèmes de cache, qui eux permettent de changer les valeurs au fil du temps ...

Moi ce que je voulais dire c'est que si tu stockes tes données dans des variables statiques en les récupérant du cache, il faut le faire une par une et non pas pour toute la classe. En gros, utiliser un cache dans ta requête par dessus le cache APC/memcached/etc.