Optimisation de regexp et autres...

Eléphant du PHP | 209 Messages

07 mai 2009, 19:12

Salut,

Je me pose une question existentielle :lol:

Je me suis dit qu'en réduisant mes six regexp à deux je gagnerai en performances. Seulement voila, c'est pas si facile :s... En plus, je me demande si le raisonnement qui conciste à dire qu'avec une seule grosse regexp, on ne parcourt la chaîne qu'une fois, et donc on n'est plus rapide, est juste.

Autre chose, toujours sur les performances : est-ce que lorsque l'on fait du traitement de chaînes, le fait de passer en paramètres des références économise la mémoire ou non ? (J'imagine que php passe la référence par défaut, mais c'est pour avoir confirmation...).

Merci.

ViPHP
ViPHP | 3300 Messages

07 mai 2009, 19:41

moins y'a de regexp mieux c'est, du point de vue performance donc c'est une très bonne idée de remplacer ca par des trucs à base de explode et de count ou de strpos, en revanche il est parfois préférable de faire du regexp quand les regles de filtrage sont particulierement velues.
Fait du php depuis que ca existe ou presque :)

ViPHP
ViPHP | 4039 Messages

07 mai 2009, 21:04

et encore faut-il optimiser les regex eux-mêmes.. un bon regex n'est pas forcément lent, mais un mauvais peut l'être très rapidement. Mais comme l'a dit nagol, une solution a base de manipulation des chaines est plus rapide.
Mais qu'importe. (je suis ici - dernier petit projet)
Berze going social.

Eléphant du PHP | 209 Messages

08 mai 2009, 19:44

Ok
Ça confirme mes pensées.
Je pense pouvoir réduire le nombre de preg_replace en utilisant preg_replace_callback, ce que je vais faire...
Merci.

ViPHP
ViPHP | 4674 Messages

09 mai 2009, 01:00

Hey :),

Oui mais non.
Une expression régulière n'est rien d'autre que l'expression d'un langage régulier, soit une syntaxe pour représenter un automate qui vérifie une grammaire régulière (cf. théorie des langages, première année).
Que fait PHP lorsqu'il rencontre une expression régulière ? Il la compile. Malheureusement, pas de système de cache des machines/automates compilés (j'ai pourtant cherché, mais je n'ai rien trouvé, et je n'arrive pas à forcer PHP à le faire).
Est-ce que la compilation est longue ? Oui.
Est-ce qu'on peut optimiser les expressions régulières ? Bien sûr. On les représente sous forme d'automate ou de grammaire et on applique des règles simplistes (toujours vues en première année) et on peut réussir à les optimiser.
Est-ce qu'une manipulation de chaînes est moins coûteuse ? Ça dépend, la réponse n'est pas prédictible de manière générale. Il faut analyser chaque cas, un par un.

Les chaînes de caractères dans PHP sont particulières. Beaucoup de langages (à l'instar du C, C++, Java etc.) considèrent une chaîne de caractères comme étant un tableau de caractères. Logique. Plus la chaîne est grande, plus le tableau est grand, et donc plus il faut de zone mémoire contiguë pour la stocker. La copie est donc coûteuse car possiblement longue. En effet, scanner toute la mémoire à la recherche d'une zone contiguë suffisamment grande est longue. D'autant plus que si toute la mémoire a été lue et qu'aucun emplacement n'est suffisament grand, alors il faut fragmenter la mémoire. Peut-être qu'on aura du swap (mémoire vers disque ou disque vers mémoire) ce qui est très très long (cheminement + lecture du disque). Et qui dit fragmentation, dit aussi segmentation, gestion de pages et tout le toutime (cf, gestion des OS, première année).
Mais dans PHP, c'est différent. L'interpréteur considère toutes les chaînes simplement guillemetées (comprendre, entourées de guillemets simples) comme des constantes (tada !). Les chaînes doublement guillemetées sont évaluées puis je-ne-sais-plus-ées.
Premièrement donc, il faut utiliser au maximum les chaînes avec des guillemets simples. Plus rapide pour PHP.
Secondement, passer une référence est forcément moins coûteuse en mémoire (et en temps) que de passer une valeur. Néanmoins, comme PHP considère que ce sont des constantes (c'est à dire que ça a un emplacement mémoire particulier, que l'on pourrait appeler statique), il les traite très rapidement. Il faut voir les cas à l'utilisation. Manipuler une chaîne de 16 caractères est totalement négligeable. Manipuler une chaîne de 16 millions de caractères est une autre histoire, et oui, il faut taper sur les références.

Autre considération : PHP ne sert pas à faire du bas-niveau. Le système de référence est présent pour profiter du système de pointeur dans le sens où on peut manipuler une même données à plusieurs endroits simultanément (i.e. un objet est envoyé dans une méthode, on le triture, mais on peut aussi l'envoyer autre part, les modifications auront été prises, même si on est à un autre endroit du programme), et non pas pour faire de l'optimisation. Si tu veux faire des programmes très optimisés, alors il faut passer au C ;).
Modifié en dernier par Hywan le 10 mai 2009, 16:23, modifié 1 fois.
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

ViPHP
ViPHP | 3300 Messages

09 mai 2009, 01:45

pour ceux qui ne veulent pas lire le paté d'hyWaN il dit comme moi mais avec plus de mots compliqués :)
Fait du php depuis que ca existe ou presque :)

Mammouth du PHP | 991 Messages

09 mai 2009, 09:06

Hey :),
Premièrement donc, il faut utiliser au maximum les chaînes avec des guillemets simples. Plus rapide pour PHP.

Voila aussi une partie importante ^^.

:langue:
DevOps, Symfony4, Hoa

Eléphant du PHP | 209 Messages

09 mai 2009, 11:28

Merci HyWaN c'est très clair :wink: .

Bon évidemment, j'utilisais déjà les passages par référence pour les optimisations.
Et par contre, concernant mes regexp, qui auraient sûrement été énormes, je pense qu'une analyse caractère par caractère sera effectivement bien plus rapide, car en procédant de cette façon je ne parcours la chaine que 2 fois, la complexité doit donc être bien plus faible que celle de 6 regexps simples réduites en deux regexps compliquées...

Il me reste une remarque liée à ce qui vient d'être dit dans le post précédent... J'étais au courant pour les guillemets simples (') et leur meilleure performances face aux "... Cependant, il se trouve que je récupère mon texte avec la fonction file_get_contents, alors comment cela est-il traité ? Comme un chaîne au sens constante ou non ?

ViPHP
ViPHP | 3300 Messages

09 mai 2009, 18:13

j'imagine oui, un file_get_contents c'est jamais qu'un fopen/fgets/fclose en une commande, y'a pas de raison qu'il t'évalues le truc.
Fait du php depuis que ca existe ou presque :)

Eléphant du PHP | 209 Messages

09 mai 2009, 22:27

Ça me rassure ;)

Par contre je me pose aussi une autre question : Comment récupère-t-on le premier et le second caractère d'une chaîne par référence ?
J'aurais imaginé quelque chose de similaire au c comme &*chaine... M'enfin le c et moi ça fait presque 2.

Mammouth du PHP | 693 Messages

09 mai 2009, 22:31

Le PHP n'utilise pas les pointeurs. Que tu passe une variable par référence ou que ce soit une copie, tu traite ta variable de la même façon.

Dans ce cas, pour obtenir le premier ou deuxième caractère, il suffit de faire $chaine[0], $chaine[1], etc...

ViPHP
ViPHP | 3300 Messages

10 mai 2009, 01:48

Le PHP n'utilise pas les pointeurs. Que tu passe une variable par référence ou que ce soit une copie, tu traite ta variable de la même façon.

Dans ce cas, pour obtenir le premier ou deuxième caractère, il suffit de faire $chaine[0], $chaine[1], etc...
absolutely
d'ailleurs jvois pas bien le pourquoi de la remarque sur les références et l'optimisation, le pasage en référence c'est juste un truc dans le toolset pour coder comme on veut, y'a pas d'optimisation relative à ça ou alors j'ai loupé quelquechose (moi jdis pas non, si on veut bien m'instruire pour une fois :))
Fait du php depuis que ca existe ou presque :)

ViPHP
ViPHP | 4674 Messages

10 mai 2009, 16:40

Une expression régulière, on a dit que c'était un automate. Un automate ça marche comment ? On a une pile, des états et des relations entre les états. La pile c'est notre chaîne de caractères. Nos états ce sont des checkpoints qui valident notre expression. Et les relations expriment le chemin à suivre dans les états. Typiquement : on reçoit un a, mais on veut un b derrière. Si j'ai autre chose, on sort vers une erreur. Soit 3 états.
Chaque entré dans la pile est un caractère de la chaîne. Donc le traitement s'effectue caractère par caractère.

Franchement, il ne faut pas avoir peur des expressions régulières, c'est très rapide malgré ce qu'on peut en dire. Je m'explique. Si on doit faire 25 manipulations de chaînes, c'est à peu près 25 copies de micro-chaînes découpées, tronquées, concaténnées, et bidouillées. Niveau mémoire et traitement, ça pu un max. Alors que si on analyse la chaîne avec une expression régulière, ce sera nettement plus rapide.
D'autant plus que les automates possibles avec une expression régulière ne sont jamais extrêmement lourd. Si on bossait sur des langages algébriques ou machines de Turing, je ne dirais pas, mais là ...

Tout dépend de tes expressions régulières encore une fois :-).

Concernant file_get_contents(), c'est la façon la plus rapide de lire un fichier dans PHP. Cette fonction effectue bien un bête fopen(), mais n'utilise pas un fgetc() ou fread() bidon. Elle utilise des techniques de correspondances de mémoires (memory mapping) pour lire plus rapidement (le tout, adapté à chaque OS, que demande le peuple ?). Enfin oui, un bête fclose().
Seulement, comme tout est fait directement en C, pas besoin de tout retranscrire en ressource pour PHP, c'es plus rapide. À préférer donc !
Et le résultat n'est évidemment pas évalué, il est donné tel quel à PHP, soit comme une chaîne simplement guillemetée.

Enfin, même si PHP ne considère pas les chaînes de caractères comme des tableaux avec son interpréteur, son analyseur lui, le considère comme tel ! Donc $string[42] va nous retourner le 41ème caractère ;-). On peut également faire $string{42} (on utilise les curly braces), mais c'est plus lent (même si négligeable).

À Nagol : qu'est-ce que tu appelles le toolset ?

Ah oui, rien ne vaut un bon cache d'opcode pour booster vos applications ;-).
« Un handicap est le résultat d'une rencontre entre une déficience ou différence et une incapacité de la société à répondre à celle-ci. »

Hoa : http://hoa-project.net (sur @hoaproject).

Mammouth du PHP | 1668 Messages

10 mai 2009, 17:19

Escusez moi


Pour apporter ma pierre à l'édifice, j'ai lut sur le livre PHP 5
avancé, à la fin du chapitre que pour les structure contenant
de | (ou pipe), il valait mieux positionner les possibilités par
probabilité d'apparition, du plus au moins.
Modifié en dernier par katagoto le 10 mai 2009, 18:58, modifié 1 fois.
"À ceux qui poursuivent leurs rêves et se spécialisent dans l'impossible" Joseph Kong

10 ans de PHP, déjà.

"moi jtrouve que katagoto il déchire!" Nagol

ViPHP
ViPHP | 3300 Messages

10 mai 2009, 18:09

À Nagol : qu'est-ce que tu appelles le toolset ?
littéralement boite à outil, ca se comprend non? quand on programme on a plusieurs choix pour faire une même chose, le passage en référence pour moi est strictement équivalent au non-passage en référence, ce n'est qu'une façon de programmer, ais-je raison de penser cela maître HyWaN (plus connu sous le nom de michel chevalet)
Fait du php depuis que ca existe ou presque :)