Manipulation sécurisée de fichier + Fichiers de données php

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

18 juin 2005, 23:19

Ce sujet est tiré d'une discussion interne, qui a dérivé sur une série de bench pour comparer deux méthodes de stockage de données in-file. Il semble que les résultats puissent être utiles à tous, et le débat est ouvert ;)





1. Manipulation sécurisée de fichiers

La manipulation de fichier sous windows nécessite l'emploi des verrous, pour gérer les accès concurrents en écriture.
En utilisant cette classe on simplifie les choses:
class Fichier {

    var $__pointeur;

    function Fichier($fichier, $mode = 'r') {
        $this->__pointeur = fopen($fichier, $mode);
        if ($this->__pointeur)
            flock($this->__pointeur, $mode=='r' ? LOCK_SH : LOCK_EX);
    }

    function ecrire($chaine) {
        return fputs($this->__pointeur, $chaine);
    }

    function lire($longueur = false) {
        if ($longueur)
            return fgets($this->__pointeur, $longueur);
        else
            return fgets($this->__pointeur);
    }

    function & pointeur() {
        return $this->__pointeur;
    }

    function fermer() {
        flock($this->__pointeur, LOCK_UN);
        fclose($this->__pointeur);
    }

}
On a accès aux fonctions de base : ouvrir, lire, ecrire, fermer. Sauf que là on gère le verrou de façon transparente. Par exemple si on effectue le test suivant, cela devrait être convaincant :
script1.php
$f = new Fichier('bidule', 'w');
sleep(10.0); // on simule une écriture qui dure 10 secondes
$f->ecrire('...');
$f->fermer();
script2.php
$f = new Fichier('bidule', 'w');
sleep(10.0); // on simule une écriture qui dure 10 secondes
$f->ecrire('!!!');
$f->fermer();
Si on lance les deux scripts en même temps, celui qui a tenté d'accèder au fichier en deuxième devra attendre que le premier ait fini son opération. Sans les verrous sous windows on se retrouve avec un fichier contenant un joyeux mélange des deux tentatives d'écriture ;)


2. Fichier variable

L'utilisation de var_export permet une application très sympa : le stockage de donnée directement dans un fichier PHP, sans passer par la serialisation (ce qui offre de bien meilleures performances).
Cela ne fonctionne pas correctement avec les objets, donc dans le cas d'un objet il vaut mieux passer par la sérialisation.

EDIT : Au vu de la suite du sujet, et des tests effectués, la lenteur de l'include par rapport à la lecture directe d'un fichier (même si cette lecture est suivie d'un unserialize), j'ai modifié ma classe qui n'utilise QUE la sérialisation.

Bref, du coup j'ai écrit cette classe (qui nécessite la précédente) :
// requis : manipulation sécurisée de fichiers
require_once 'fichier.class.php';

// classe définissant un fichier contenant une valeur
// wrapper de serialisation
// gzip ne devrait être activé que si le poids des fichiers est un facteur critique
// Ecriture 7 à 8 fois plus lente - Lecture 1.3 fois plus lente - Poids 4 fois moindre
class FichierVariable {

    var $__valeur;
    var $__fichier;
    var $__gzip;

    // constructeur : $fichier = nom du fichier
    function FichierVariable($fichier, $gzip = false) {
        $this->__gzip = $gzip;
        $this->lire($fichier);
    }

    // active ou désactive la compression gzip
    function gzip($gzip = true) {
        $this->__gzip = $gzip;
    }

    // renvoie la valeur stockée dans le fichier
    function valeur() {
        return $this->__valeur;
    }

    // définit la valeur stockée dans le fichier
    // cette modification n'est pas enregistrée tant qu'on n'a pas appelé la méthode sauve()
    function definir($valeur) {
        $this->__valeur = $valeur;
    }

    // lit la valeur dans le fichier
    function lire($fichier = false) {
        if ($fichier)
            $this->__fichier = $fichier;
        if (!is_file($this->__fichier)) {
            $this->__valeur = NULL;
            return false;
        }
        else {
            $contenu = file_get_contents($this->__fichier);
            if ($this->__gzip)
                $contenu = gzuncompress($contenu);
            $this->__valeur = unserialize($contenu);
            return true;
        }
    }

    // enregistre les modifications dans le fichier
    // renvoie true ou false selon la valeur de succès
    function ecrire($fichier = false) {
        if ($fichier)
            $this->__fichier = $fichier;
        $f = new Fichier($this->__fichier, 'wb');
        if (!$f)
            return false;
        $contenu = serialize($this->__valeur);
        if ($this->__gzip)
            $contenu = gzcompress($contenu,9);
        if (!$f->ecrire($contenu))
            return false;
        $f->fermer();
        return true;
    }

}
Modifié en dernier par naholyr le 20 juin 2005, 06:32, modifié 2 fois.

ViPHP
ViPHP | 1380 Messages

19 juin 2005, 12:25

J'ai essayé ton code d'accès concurrent à un même fichier et, conformément à la doc, ça ne pose aucun problème sous Linux.

Et en attendant, j'ai plus été intéressé par la partie 'serialize' contre 'var_export'.

J'ai fait un essai sur un gros tableau multiD:
array(array(2000 éléments, 500 éléments), 500 éléments)

Mais mes résultats ne vont pas dans ton sens:

Code : Tout sélectionner

serialize --> fwrite --> file_get_contents --> unserialize 0.015820980072 sec. taille fichier 67914 export_var --> fwrite --> include 0.0401771068573 sec. taille fichier 136433
var_export est beaucoup plus verbeux que la chaîne produite par serialize.

Dans quel cas cette fonction est-elle plus rapide?
ripat

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

19 juin 2005, 13:38

J'ai fait un essai sur un gros tableau multiD:
array(array(2000 éléments, 500 éléments), 500 éléments)

Mais mes résultats ne vont pas dans ton sens:

Code : Tout sélectionner

serialize --> fwrite --> file_get_contents --> unserialize 0.015820980072 sec. taille fichier 67914 export_var --> fwrite --> include 0.0401771068573 sec. taille fichier 136433
var_export est beaucoup plus verbeux que la chaîne produite par serialize.

Dans quel cas cette fonction est-elle plus rapide?
Tu fais une lecture pour une ecriture.
En pratique on a bien plus de lectures que d'écritures, je pense que si tu fais une ecriture suivie de 100 lectures ce sera différent. Maintenant je n'ai pas fait de test précis, j'ai simplement suivi un message dans un newsgroup qui préconisait var_export car l'include est bien plus rapide qu'une lecture + une désérialisation.

Et puis je ne suis pas en accord avec tes résultats, qui ont l'air tiré d'une seule exécution. Il faut faire une moyenne ;)

Voici ma fonction de bench
<?php

function microtime_float()
{
   list($usec, $sec) = explode(" ", microtime());
   return ((float)$usec + (float)$sec);
}

function start_bench($id = 0)
{
    global $__bench__starts;
    if (!isset($__bench__starts))
        $__bench__starts = array();
    $__bench__starts[$id] = microtime_float();
}

function end_bench($id = 0)
{
    global $__bench__starts;
    $time = microtime_float();
    $start = $__bench__starts[$id];
    unset($__bench__starts[$id]);
    return $time-$start;
}

?>
Voici le script que j'ai utilisé pour comparer var_export et serialize en écriture
<?php

// construction du tableau de bourrin :P
$tab = array(array(array(),array()),array());
for ($i=0; $i<2000; ++$i)
    $tab[0][0][] = mt_rand(1,5000);
for ($i=0; $i<500; ++$i)
    $tab[0][1][] = mt_rand(1,5000);
for ($i=0; $i<500; ++$i)
    $tab[1][] = mt_rand(1,5000);

// début du test
include 'bench.php';
include 'fichier.class.php';

// méthode "serialize"
$temps = array();
for ($i=0; $i<100; ++$i) {
    start_bench();
    $serialise = serialize($tab);
    $f = new Fichier('serialize.txt', 'w');
    $f->ecrire($serialise);
    $f->fermer();
    $temps[] = end_bench();
}
$nb = coun($temps);
$temps_moyen = array_sum($temps)/$nb;
$poids = filesize('serialize.txt');
echo "Serialize (moyennes sur $nb exécutions) :\r\n";
echo "\tTemps : $temps_moyen s.\r\n";
echo "\tPoids : $poids o.\r\n";

// méthode "var_export"
$temps = array();
for ($i=0; $i<100; ++$i) {
    start_bench();
    $varexport = var_export($tab,true);
    $f = new Fichier('varexport.txt', 'w');
    $f->ecrire('<'.'?php return '.$varexport.'; ?'.'>');
    $f->fermer();
    $temps[] = end_bench();
}
$nb = coun($temps);
$temps_moyen = array_sum($temps)/$nb;
$poids = filesize('serialize.txt');
echo "Var_Export (moyennes sur $nb exécutions) :\r\n";
echo "\tTemps : $temps_moyen s.\r\n";
echo "\tPoids : $poids o.\r\n";

?>
Et voici le résultat
Serialize (moyennes sur 500 exécutions) :
Temps : 0.0286038117409 s.
Poids : 39054 o.
Var_Export (moyennes sur 500 exécutions) :
Temps : 0.0130394721031 s.
Poids : 56131 o.
Donc déjà en écriture, sur 500 exécutions, la méthode var_export se révèle plus rapide.

Ensuite en lecture
<?php

// début du test
include 'bench.php';
include 'fichier.class.php';

// méthode "serialize"
$temps = array();
for ($i=0; $i<500; ++$i) {
    start_bench();
    $serialise = file_get_contents('serialize.txt');
    $tab = unserialize($serialise);
    unset($tab);
    $temps[] = end_bench();
}
$nb = count($temps);
$temps_moyen = array_sum($temps)/$nb;
$poids = filesize('serialize.txt');
echo "Serialize (moyennes sur $nb exécutions) :\r\n";
echo "\tTemps : $temps_moyen s.\r\n";

// méthode "var_export"
$temps = array();
for ($i=0; $i<500; ++$i) {
    start_bench();
    $tab = include 'varexport.txt';
    unset($tab);
    $temps[] = end_bench();
}
$nb = count($temps);
$temps_moyen = array_sum($temps)/$nb;
$poids = filesize('varexport.txt');
echo "Var_Export (moyennes sur $nb exécutions) :\r\n";
echo "\tTemps : $temps_moyen s.\r\n";

?>
Et le résultat
Serialize (moyennes sur 500 exécutions) :
Temps : 0.0128675489426 s.
Var_Export (moyennes sur 500 exécutions) :
Temps : 0.0338353643417 s.
Et là je suis sous le choc... C'est l'écriture qui en patit le plus...

J'aurais mieux fait de bencher avant :lol:

Bon ben je remballe mon var_export...

Quand-même avant abandon total j'essaie avec une donnée plus petite : un tableau de 500 éléments.
Ecriture
Serialize (moyennes sur 500 exécutions) :
Temps : 0.00351489830017 s.
Poids : 6282 o.
Var_Export (moyennes sur 500 exécutions) :
Temps : 0.00352359199524 s.
Poids : 7300 o.
Lecture
Serialize (moyennes sur 500 exécutions) :
Temps : 0.00170826005936 s.
Var_Export (moyennes sur 500 exécutions) :
Temps : 0.00533777856827 s.
Encore pire...

Est-ce que vous vous rendez compte de ce que ça signifie ? Les include sont une perte phénoménale en terme de performances !

C'est un constat assez gênant tout de même...

Mammouth du PHP | 19672 Messages

19 juin 2005, 13:45

Messieurs, si je peux émettre une suggestion: ce débat d'experts gagnerait à pouvoir être suivi par d'autres sur le forum des développeurs, il n'est pas exclu que d'autres spécialistes puissent apporter un éclairage différents pour le bénéfice de tout le monde ... :-k
Codez en pensant que celui qui maintiendra votre code est un psychopathe qui connait votre adresse :axe:

Eléphant du PHP | 287 Messages

19 juin 2005, 16:04

y'a un truc que je ne comprend pas dans votre délire.

pour ce qui est de serialize je ne connait pas.
par contre pour ce qui est de var_export...

je m'explique, les fois où j'ai dû utilisé var_export il était couplé avec eval().
de ton côté naholyr tu proposes de passer par une méthode include pour remplir ta variable.

un p'tit script:
<?php

$fh=fopen('toto.txt','w');

$tab[0]=1;
$tab[1]=2;

var_export($tab,TRUE);

fwrite($fh,var_export($tab,TRUE));

//fonctions à décommenter à discrétion
//method_eval();
//method_include();

function method_eval()
{
	$fich=file_get_contents('toto.txt');
	eval('$tab='.$fich.';');

	echo('$fich[1]: '.$fich[1].'<br>');
	echo('$tab[1]: '.$tab[1]);

}


function method_include()
{
	$tab=include 'toto.txt';
	echo('<br>$tab[1]: '.$tab[1]);
	
}


?>
tout ça pour dire qu'avec une méthode include() je ne peux pas récupérer les valeurs de mon tableau(en plus j'ai droit à l'affichage du contenu de mon fichier et ça m'étonne que ça ne le fasse pas pour vous).

en conclusion je ne vois pas ce qui est testé :roll:

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

19 juin 2005, 16:09

Si ton fichier était de cette forme:
<?php return array(...); ?>
La fonction include renverrait la valeur enregistrée.

Dans le doute, on lit la doc :langue:
Gestion du retour : il est possible d'exécuter une commande return() dans un fichier inclus pour en terminer le traitement et retourner au fichier appelant. De plus, il est possible de retourner des valeurs des fichiers inclus. Vous pouvez prendre et traiter la valeur retournée par la fonction, comme toute autre fonction.

ViPHP
ViPHP | 1380 Messages

19 juin 2005, 16:16

J'ai corrigé mon bench (ou devrais-je dire banc d'essai??) pour tenir compte de ta remarque justifiée.

Pour chaque méthode j'ai fait une écriture d'un tableau de 500 éléments, suivie par 100 lectures. Et chaque cycle 50 fois pour lisser les crêtes. (plus de cycles n'améliorera pas la qualité de la moyenne).

Mes résultats rejoignent les tiens:

Code : Tout sélectionner

Serialize 9.56083798409 sec. 18910 octets var_export avec include 24.0332579613 sec. 26988 octets
J'ai également essayé avec eval(var_export) au lieu d'un include et c'est pas (beaucoup) mieux:

Le code:
$nb_batch = 50;
$nb_lectures = 100;

$batch = $nb_batch;
timing(0);
do{
  $lec = $nb_lectures;
  $exp = var_export($tableau3d, true);
  $exp = '$ret = '.$exp.';';
  $f = fopen('fichier_var3', 'w');
  fwrite($f, $exp);
  fclose($f);
  do{
    eval(file_get_contents('fichier_var3'));
  }while ($lec--);
}while ($batch--);
timing();
Les résultats:

Code : Tout sélectionner

var_export avec eval 23.3266990185 sec. 26966 octets
Par ailleurs, les variables de session sont stockées, côté serveur, dans un format identique à celui de serialize. Je me dis donc que ce n'est pas sans raisons.

Par contre j'ai envie de comparer le stockage de données de petite dimension en fichier plat et en table MySQL (genre fichier de paramètres ou de session).

Pour des application simples, il n'est pas certain que MySQL soit plus rapide (mysql_pconnect --> mysql_select_db --> mysql_query --> mysql_fetch_row).

Au point de vue recherche de lignes, j'ai eu l'occasion de m'apercevoir qu'une utilisation appropriée des regex était (beaucoup) plus rapide que de parcourir tout un tableau pour trouver les lignes recherchées. J'ai même fait un parseur de pseudo-sql pour des fichiers textes. Il faudrait que je le dépoussière...

Je ne l'ai jamais terminé car je ne pensais pas qu'il y aurait de la demande pour l'utilisation de fichiers plats pour le stockage de données. Le post de Naholyr me laisse penser que l'utilisation de ce type de fichier n'est pas tout à fait mort. :wink:
ripat

Eléphant du PHP | 287 Messages

19 juin 2005, 16:16

bon à savoir :)

edit->
Au point de vue recherche de lignes, j'ai eu l'occasion de m'apercevoir qu'une utilisation appropriée des regex était (beaucoup) plus rapide que de parcourir tout un tableau pour trouver les lignes recherchées.
est ce que tu as essayer les fonctions natives de php du type array_search() ,array_keys() ou encore array_filter().
Dans le doute, on lit la doc Tirer la langue
c'est malin :roll:

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

19 juin 2005, 16:41

Je me suis dit que ces temps à la lecture s'expliquait par la quantité d'espaces inutiles générés par var_export pour les tableaux.
J'ai donc fait une procédure "var_export_clean" qui prend le cas particulier des tableaux (algo récursif) pour éviter ces espaces inutiles.

J'obtiens ces résultats:

Code : Tout sélectionner

>php -f test_ecrit.php Serialize (moyennes sur 20 exécutions) : Temps : 0.0288022756577 s. Poids : 39089 o. Var_Export (moyennes sur 20 exécutions) : Temps : 0.0143486976624 s. Poids : 56166 o. Var_Export nettoyé (moyennes sur 20 exécutions) : Temps : 0.207546901703 s. Poids : 30104 o. >Exit code: 0 >php -f test_lit.php Serialize (moyennes sur 500 exécutions) : Temps : 0.0122645463943 s. Var_Export (moyennes sur 500 exécutions) : Temps : 0.0335539860725 s. Var_Export nettoyé (moyennes sur 500 exécutions) : Temps : 0.0303982906342 s. >Exit code: 0
La méthode "var_export_clean" est bien plus lente à l'exécution (normal, d'autant plus que je n'ai fait aucun effort d'optimisation) mais ce n'est pas ce qui est intéressant.

On obtient un fichier plus léger qu'avec serialize (c'est le résultat attendu). Mais l'évaluation de ce code avec un include est plus lente qu'une lecture du fichier + un appel à unserialize.

Je trouve ces résultats vraiment étonnants. Qu'une évaluation directe de code soit plus lente qu'une désérialisation (et pas qu'un peu, c'est d'ordre 3 quand-même), ça me dépasse...

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

19 juin 2005, 16:54

Je ne l'ai jamais terminé car je ne pensais pas qu'il y aurait de la demande pour l'utilisation de fichiers plats pour le stockage de données. Le post de Naholyr me laisse penser que l'utilisation de ce type de fichier n'est pas tout à fait mort. :wink:
:arrow: SQLite :?:


J'ajoute ces derniers tests :
<?php

set_time_limit(0);

// construction du tableau de bourrin :P
$tab = array(array(), array(array(),array()));
for ($i=0; $i<500; ++$i)
    $tab[0][] = mt_rand(1,5000);
for ($i=0; $i<2000; ++$i)
    $tab[1][0][] = mt_rand(1,5000);
for ($i=0; $i<500; ++$i)
    $tab[1][1][] = mt_rand(1,5000);

// début du test
include 'bench.php';
include 'fichier.class.php';

// méthodes
function serialize1_ecrit() {
    global $tab;
    $f = new Fichier('serialize1.txt', 'w');
    $f->ecrire(serialize($tab));
    $f->fermer();
}
function serialize2_ecrit() {
    global $tab;
    $f = new Fichier('serialize2.txt', 'w');
    $f->ecrire('<'.'?php return unserialize(\''.str_replace('\'','\\\'',serialize($tab)).'\'); ?'.'>');
    $f->fermer();
}
function varexport1_ecrit() {
    global $tab;
    $f = new Fichier('varexport1.txt', 'w');
    $f->ecrire(var_export($tab,true));
    $f->fermer();
}
function varexport2_ecrit() {
    global $tab;
    $f = new Fichier('varexport2.txt', 'w');
    $f->ecrire('<'.'?php return '.var_export($tab,true).'; ?'.'>');
    $f->fermer();
}
function serialize1_lit() {
    $contenu = file_get_contents('serialize1.txt');
    $tab = unserialize($contenu);
}
function serialize2_lit() {
    $tab = include 'serialize2.txt';
}
function varexport1_lit() {
    $contenu = file_get_contents('varexport1.txt');
    eval('$tab = '.$contenu.';');
}
function varexport2_lit() {
    $tab = include 'varexport2.txt';
}

// évaluations
function temps_execution($fonction) {
    start_bench();
    $fonction();
    return end_bench();
}
function evaluer($fonction) {
    $nb = 200;
    echo "Evaluation '$fonction'\r\n";
    // écriture
    echo "\tEcritures ($nb exécutions)...\r\n";
    $foo = $fonction.'_ecrit';
    $temps = 0;
    for ($i=0; $i<$nb; $i++)
        $temps += temps_execution($foo);
    echo "\t\tTemps total   : $temps s.\r\n";
    echo "\t\tPoids fichier : ".filesize($fonction.'.txt')." octets\r\n";
    // lecture
    echo "\tLectures ($nb exécutions)...\r\n";
    $foo = $fonction.'_lit';
    $temps = 0;
    for ($i=0; $i<$nb; $i++)
        $temps += temps_execution($foo);
    echo "\t\tTemps total   : $temps s.\r\n";
}
evaluer('serialize1');
evaluer('serialize2');
evaluer('varexport1');
evaluer('varexport2');

?>
  • serialize1 écriture directe du résultat de serialize() dans un fichier. lecture du fichier et appel à unserialize().
  • serialize2 écriture d'un code php valide de la forme "return unserialize('...');" avec la valeur de serialize(). lecture du fichier par include.
  • [n]varexport1[/b] écriture directe du résultat de var_export() dans un fichier. lecture du fichier et évaluation du code par eval().
  • varexport2 écriture d'un code php valide de la forme "return ...;" avec la valeur de var_export(). lecture du fichier par include
Résultats :

Code : Tout sélectionner

Evaluation 'serialize1' Ecritures (200 exécutions)... Temps total : 5.58848047256 s. Poids fichier : 39047 octets Lectures (200 exécutions)... Temps total : 4.23142194748 s. Evaluation 'serialize2' Ecritures (200 exécutions)... Temps total : 5.69463515282 s. Poids fichier : 39079 octets Lectures (200 exécutions)... Temps total : 6.92681670189 s. Evaluation 'varexport1' Ecritures (200 exécutions)... Temps total : 2.34241223335 s. Poids fichier : 56107 octets Lectures (200 exécutions)... Temps total : 8.75390481949 s. Evaluation 'varexport2' Ecritures (200 exécutions)... Temps total : 2.87869596481 s. Poids fichier : 56124 octets Lectures (200 exécutions)... Temps total : 8.2771987915 s.
On voit que l'exécution de var_export() est plus rapide que serialize(). L'écriture en utilisant var_export() est 2 fois plus rapide.

Par contre en lecture, l'évaluation directe du code (par include ou eval) est plus lente que la désérialisation.

Je m'attendais vraiment à l'exact contraire:
- il me paraissait logique que serialize soit plus rapide que var_export, puisque ce premier est souvent utilisé (et implicitement en plus, dans les sessions par exemple), et donc probablement plus optimisé.
- il me paraissait logique que l'évaluation directe de code soit plus rapide que le passage par une fonction intermédiaire comme unserialize().

J'ai encore du mal à comprendre ces résultats...

ViPHP
ViPHP | 1380 Messages

19 juin 2005, 17:52

Je trouve ces résultats vraiment étonnants. Qu'une évaluation directe de code soit plus lente qu'une désérialisation (et pas qu'un peu, c'est d'ordre 3 quand-même), ça me dépasse...
Faudrait que tu retrousses tes manches, mettes ton casque de mineur et plonges dans le code source de unserialize() et de array(). Il y a peut-être un beau petit code tout propre pour l'un et pas pour l'autre. Vas savoir! :wink:
est ce que tu as essayer les fonctions natives de php du type array_search() ,array_keys() ou encore array_filter().
Oui. L'avantage d'utiliser les regex se marque encore plus lorsqu'on cherche une partie de colonne. L'équivalent de LIKE '%mot_recherché%' en sql. Faudrait que je fasse un bench la dessus un de ces jours. Un gros fichier plat du genre :

Code : Tout sélectionner

col1;col2;col3 col1;col2;col3 col1;col2;col3
Et trouver la méthode la plus rapide pour trouver la ou les lignes qui correspondent à une requête sql simple. Du genre SELECT ..... WHERE col2 LIKE '%***%' AND col3 ='***'
ripat

Eléphant du PHP | 287 Messages

19 juin 2005, 20:50

J'ai encore du mal à comprendre ces résultats...
alors je vais essayer de t'expliquer :roll:

déja tu ne fait aucune évaluation direct du code par rapport à unserialize().
d'un côté tu as eval() qui est une fonction lente(pour t'en convaincre compare la vitesse d'exécution d'un algo que tu écrit directement et un algo que tu ecris à l'aide de eval()).
de l'autre tu as include() qui plus le fichier sera lourd plus il sera lent par rapport à file_get_contents().

un p'tit script:
<?php

$time_start = microtime_float();

for($i=0;$i<100;$i++)
{
	ser_lit();
}



$time_end = microtime_float();

$time = $time_end - $time_start;

echo('ser: '.$time);

$time_start = microtime_float();

for($i=0;$i<100;$i++)
{
	var_lit();
}



$time_end = microtime_float();

$time = $time_end - $time_start;

echo('<br>var :'.$time);


$time_start = microtime_float();

for($i=0;$i<100;$i++)
{
	direct_inc();
}



$time_end = microtime_float();

$time = $time_end - $time_start;

echo('<br>direct_inc: '.$time);

$time_start = microtime_float();

for($i=0;$i<100;$i++)
{
	direct_get();
}



$time_end = microtime_float();

$time = $time_end - $time_start;

echo('<br>direct_get :'.$time);

function microtime_float()
{
   list($usec, $sec) = explode(" ", microtime());
   return ((float)$usec + (float)$sec);
}

function  ser_lit(){
    $contenu = file_get_contents('serialize1.txt');
    $tab = unserialize($contenu);
	
}



function var_lit() {
    $toto = file_get_contents('varexport1.txt');
	eval('$tab='.$toto.';');
	
}

function direct_inc()
{
	$tab=include('varexport2.txt');
}

function direct_get()
{
	$tab=file_get_contents('varexport2.txt');
}

?>
son résultat:
ser: 0.619415998459
var :1.37596106529
direct_inc: 1.34881305695
direct_get :0.0302901268005
j'ai réutilisé les fichiers créer par ton bench(serialize:39ko et varexport:55ko).
et bien, sur créer un tableau via file_get_contents ne sert à rien vu qu'il y aura une erreur si tu tente de le faire.

cette fois je crois que je n'ais pas dit de bétise :)

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

19 juin 2005, 21:14

Comparaison entre pcre sur fichier CVS et sqlite :

Fichier CVS : un fichier de 3 colonnes <ville;codepostal;departement> de 7000 lignes.
Base SQLite : une table CodeP de 3 colonnes, même contenu (générée à partir du CVS).
<?php

include 'bench.php';


start_bench();
for ($i=0; $i<100; $i++) {
    echo '.';
    // contenu du fichier
    $contenu = file_get_contents('mabase/CodeP.dat');
    // extraction des colonnes
    $premierNL = strpos($contenu, "\n");
    $premiereLigne = substr($contenu, 0, $premierNL-1);
    $contenu = substr($contenu, $premierNL+1);
    $colonnes = explode(';', $premiereLigne);
    // exécution de 5 requêtes SELECT (on fait 5 fois la même)
    for ($j=0; $j<5; $j++) {
        // SELECT * FROM CodeP WHERE ville LIKE "A%" AND departement = "ARDECHE"
        // -> colonne0 ~ /^A/ && colonne2 = "ARDECHE"
        // -> ligne ~ /^A.*;.*;ARDECHE$/
        preg_match_all("/^A.*;.*;ARDECHE$/mi", $contenu, $resultat);
        foreach ($resultat as $ligne)
            $row = explode(';', $ligne);
    }
}
echo "\r\npreg_match : ", end_bench(), " s.\r\n";

start_bench();
for ($i=0; $i<100; $i++) {
    echo '.';
    // ouverture du la base
    $db = sqlite_open('villes.db');
    // exécution de 5 requêtes SELECT (on fait 5 fois la même)
    for ($j=0; $j<5; $j++) {
        $res = sqlite_query($db, 'SELECT * FROM CodeP WHERE ville LIKE "A%" AND departement = "ARDECHE"');
        while ($row = sqlite_fetch_array($res)) ;
    }
    sqlite_close($db);
}
echo "\r\nsqlite : ", end_bench(), " s.\r\n";

?>
Résultat :

Code : Tout sélectionner

>php -f fichiersql.class.php .................................................................................................... preg_match : 52.5584769249 s. .................................................................................................... sqlite : 10.1793990135 s. >Exit code: 0
Je pense qu'il est inutile d'espérer faire mieux ;)

ViPHP
ViPHP | 1380 Messages

19 juin 2005, 21:55

Il n'y a pas photo effectivement. Je vais donc laisser la poussière sur ma tentative de parser su sql pour des fichiers plats. Allez, tant qu'à faire, je vais même lui en remettre un bonne couche :wink:

Faudrait aussi que j'essaye sqlite. Ca m'a l'air tout simple. Pas de serveur base de données pas de connexion, rien qu'ouvrir --> requête --> fermer.
ripat

ViPHP
ViPHP | 1380 Messages

19 juin 2005, 22:07

Tiens, puisque ton code de bench est encore fumant, remplace
preg_match_all("/^A.*;.*;ARDECHE$/mi", $contenu, $resultat); 
par
preg_match_all("/^A[^;]*;[^;]*;ARDECHE$/mi", $contenu, $resultat); 
pour voir si ça change beaucoup le timing sur ton fichier de test?
ripat