/ / Les performances Perl touchent-elles deux méthodes regex courantes pour le rognage des chaînes? - regex, perl

La performance Perl a-t-elle frappé entre deux méthodes de regex courantes pour le rognage des chaînes? - regex, perl

Je travaille donc sur un script Perl qui fait une grande quantité de traitement (rien de trop compliqué, mais beaucoup de celui-ci) et a décidé de faire un petit benchmark pour comparer deux méthodes courantes de coupe des chaînes.

La première méthode est une ligne simple rapide:

$word =~ s/^s+|s+$//g;

La deuxième méthode est un peu plus longue, mais fait la même chose:

$word =~ s/^s+//;
$word =~ s/s+$//;

Pour mes repères, j'ai fait lire le script à partir d'un fichier de 40 millions de lignes, en coupant chacune (ne fait rien d'autre que ça). La longueur de ligne moyenne est inférieure à 20 octets.

La première méthode a pris en moyenne 87 secondes.
La deuxième méthode a pris en moyenne 27 secondes.
Aucun traitement (il suffit de lire la ligne, de continuer) prend en moyenne 16 secondes.

La première méthode (première passe) correspondra à tous les espaces blancs de début ou de fin, puis les supprimera, puis fera correspondre et supprimera les espaces blancs de début / fin de l'autre côté.
La deuxième méthode correspond et supprime tous les espaces blancs de début, puis correspond et supprime tous les espaces de fin.

Je me trompe peut-être ici, mais pourquoi la deuxième méthode serait-elle plus de 3 fois plus rapide que la première?

Réponses:

5 pour la réponse № 1

Il est logique que les modèles de non-retour ancrés puissent être mieux optimisés (en fait, un seul balayage séquentiel avant / arrière à partir d'une position de caractère connue);

Il y a de fortes chances que l '"option" (|) fasse reculer l'optimiseur et vous obtenez un retour en arrière standard, ce qui est très mauvais, car de nombreux espaces peuvent se produire qui ne sont pas à la fin


11 pour la réponse № 2

Le moteur regex doit faire plus de travail dans le premier cas, à savoir en reculant pour évaluer les alternatives. Vous pouvez voir la différence dans le code impliqué:

echo " hello " |perl -Mre=debug -ple "s/^s+|s+$//g"
echo " hello " |perl -Mre=debug -ple "s/^s+//;s/s+$//"

2 pour la réponse № 3

Je soupçonne que l'expression régulière Perl peut être en mesure d'optimiser la deuxième version en utilisant une analyse statique du modèle. Par exemple, il pourrait voir que /^foo/ doit correspondre au début de la chaîne. Si la correspondance échoue, il est inutile d'itérer sur le reste des caractères de la chaîne pour rechercher des correspondances.

Par défaut, le caractère "^" est garanti pour correspondre uniquement au début de la chaîne, le caractère "$" uniquement à la fin (ou avant la nouvelle ligne à la fin), et Perl fait certaines optimisations avec l'hypothèse que la chaîne ne contient qu'une seule ligne.

La source (Souligné par moi.)

La première version est une expression plus compliquée et n'est pas aussi facilement optimisée.