79 votes

Traitement de texte - performances de Python et de Perl

Voici mon script pour effectuer un traitement de texte simple à partir d'environ 21 fichiers de log, chacun d'environ 300 KB à 1 MB (maximum) x 5 fois répété (total de 125 fichiers, en raison de la journal répété 5 fois).

Code Python (le code a été modifié pour utiliser le code compilé re et en utilisant re.I )

#!/usr/bin/python

import re
import fileinput

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for line in fileinput.input():
    fn = fileinput.filename()
    currline = line.rstrip()

    mprev = exists_re.search(currline)

    if(mprev):
        xlogtime = mprev.group(1)

    mcurr = location_re.search(currline)

    if(mcurr):
        print fn, xlogtime, mcurr.group(1)

Code Perl

#!/usr/bin/perl

while (<>) {
    chomp;

    if (m/^(.*?) INFO.*Such a record already exists/i) {
        $xlogtime = $1;
    }

    if (m/^AwbLocation (.*?) insert into/i) {
        print "$ARGV $xlogtime $1\n";
    }
}

Et, sur mon PC, les deux codes génèrent exactement le même fichier de résultat de 10 790 lignes. Et, voici le chronométrage effectué sur les implémentations Perl et Python de Cygwin.

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.py *log* *log* *log* *log* *log* >
summarypy.log

real    0m8.185s
user    0m8.018s
sys     0m0.092s

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.pl *log* *log* *log* *log* *log* >
summarypl.log

real    0m1.481s
user    0m1.294s
sys     0m0.124s

À l'origine, il fallait 10,2 secondes avec Python et seulement 1,9 seconde avec Perl pour ce simple traitement de texte.

(UPDATE) mais, après la compilation de l re version de Python, il faut maintenant 8,2 secondes en Python et 1,5 seconde en Perl. Perl est tout de même beaucoup plus rapide.

Existe-t-il un moyen d'améliorer la vitesse de Python OU il est évident que Perl sera le plus rapide pour le traitement de texte simple.

D'ailleurs, ce n'est pas le seul test que j'ai fait pour un simple traitement de texte... Et, chaque fois que je fais le code source d'une manière différente, Perl gagne toujours de loin. Et, pas une seule fois Python n'a été plus performant pour un simple m/regex/ correspondre et imprimer des trucs.

Ne suggérez pas l'utilisation de C, C++, Assembly, ou d'autres variantes de Python, etc.

Je cherche une solution en utilisant Python standard avec ses fonctions intégrées modules intégrés par rapport à Perl standard (sans même utiliser les modules). Mon garçon, je souhaite utiliser Python pour toutes mes tâches en raison de sa lisibilité, mais renoncer à la vitesse, je ne le pense pas.

Donc, s'il vous plaît, suggérez comment le code peut être amélioré pour avoir des données comparables. résultats comparables à ceux de Perl.

MISE À JOUR : 2012-10-18

Comme d'autres utilisateurs l'ont suggéré, Perl a sa place et Python la sienne.

Ainsi, pour cette question, on peut conclure sans risque que pour une simple correspondance regex sur chaque ligne pour des centaines ou des milliers de fichiers texte et l'écriture des résultats dans un fichier (ou l'impression à l'écran), Perl gagnera toujours, toujours, en performance pour ce travail. C'est aussi simple que cela.

Veuillez noter que lorsque je dis que Perl gagne en performance... seuls Perl et Python standard sont comparés... sans recourir à certains modules obscurs (obscurs pour un utilisateur normal comme moi) et sans appeler les bibliothèques C, C++, assembly depuis Python ou Perl. Nous n'avons pas le temps d'apprendre toutes ces étapes et installations supplémentaires pour un simple travail de correspondance de texte.

Donc, Perl est excellent pour le traitement de texte et les regex.

Python a sa place pour faire du rock dans d'autres endroits.

Mise à jour 2013-05-29 : Un excellent article qui fait une comparaison similaire est ici . Perl l'emporte à nouveau pour la correspondance de texte simple... Et pour plus de détails, lisez l'article.

0 votes

Les motifs sont-ils compilés une seule fois en Python (comme en Perl) ?

0 votes

Les deux programmes sont-ils équivalents ? Je ne vois rien comme /i dans la version Python.

0 votes

Ils ne sont pas totalement équivalents ( (?i) o re.I devrait être ajouté pour Python), mais très proche.

19voto

Josh Wright Points 1723

C'est exactement le genre de choses pour lesquelles Perl a été conçu, et je ne suis donc pas surpris qu'il soit plus rapide.

Une optimisation facile de votre code Python serait de précompiler ces regex, afin qu'ils ne soient pas recompilés à chaque fois.

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists')
location_re = re.compile(r'^AwbLocation (.*?) insert into')

Et ensuite dans votre boucle :

mprev = exists_re.search(currline)

et

mcurr = location_re.search(currline)

En soi, cela ne mettra pas magiquement votre script Python en ligne avec votre script Perl, mais appeler de façon répétée re dans une boucle sans compiler d'abord est une mauvaise pratique en Python.

3 votes

re met en cache les regex récemment utilisés, donc ce n'est probablement pas un gros problème.

7 votes

@nneonneo J'ai entendu cela de nombreuses fois et j'ai vu les lignes dans le re le code source qui effectue la mise en cache. Mais d'une manière ou d'une autre, je n'ai jamais vu de benchmark qui place les deux dans le même ordre de grandeur, mais plusieurs benchmarks (dont un rapide et sale que j'ai fait il y a une seconde) qui placent l'option de précompilation à plusieurs fois plus rapide.

3 votes

Intéressant. Eh bien, c'est définitivement une bonne pratique de précompiler les regex, mais je n'ai pas vraiment prêté attention à l'écart de performance. Vous voulez partager les chiffres ?

14voto

ikegami Points 133140

Hypothèse : Perl passe moins de temps à revenir en arrière dans les lignes qui ne correspondent pas en raison des optimisations qu'il possède et que Python ne possède pas.

Qu'obtenez-vous en remplaçant

^(.*?) INFO.*Such a record already exists

avec

^((?:(?! INFO).)*?) INFO.*Such a record already 

o

^(?>(.*?) INFO).*Such a record already exists

4voto

Don O'Donnell Points 1687

Les appels de fonction sont un peu coûteux en termes de temps en Python. Et pourtant, vous avez un appel de fonction invariant pour obtenir le nom du fichier à l'intérieur de la boucle :

fn = fileinput.filename()

Déplacez cette ligne au-dessus de la for et vous devriez voir une amélioration de votre timing Python. Mais probablement pas assez pour battre Perl.

1 votes

+1 pour le bon œil, mais... Eh bien, mais le nom du fichier change. Ce n'est pas un invariant de la boucle. De toute façon, il peut être plus rapide de ne pas utiliser la fonction fileinput et ajouter une autre boucle externe à travers les noms de fichiers. Le nom de fichier serait alors l'invariant.

1 votes

Un point intéressant, mais cela doit être minuscule par rapport au temps de traitement de deux regex.

3voto

ihightower Points 459

@pepr Merci. Votre code s'exécute en 6,1 secondes (environ 2 secondes d'amélioration) par rapport aux 1,8 secondes de perl**.

Mais, bon sang, c'est sacrément compliqué de se creuser la tête avec ça. code pour un utilisateur moyen (moi) qui se trouve à suivre des exemples rapides du livre à l'utilisation réelle.

Par rapport au code de perl, le code de python n'aide pas beaucoup pour lisibilité... mais il y a tellement de boucles... et pour finir, il ne s'approche même pas des performances de perl. ne s'approche même pas des performances de perl. Dans tous les cas, d'autres suggestions sont les bienvenues.

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file_pepr.py *log* *log* *log* *log* *lo
g* > summarypy_pepr.log

real    0m6.089s
user    0m5.772s
sys     0m0.155s

2voto

jrd1 Points 4648

En général, tous les repères artificiels sont mauvais. Toutefois, toutes choses étant égales par ailleurs (approche algorithmique), vous pouvez apporter des améliorations sur une base relative. Il faut toutefois noter que je n'utilise pas Perl, je ne peux donc pas plaider en sa faveur. Cela dit, avec Python, vous pouvez essayer d'utiliser Pyrex o Cython pour améliorer les performances. Ou, si vous êtes aventureux, vous pouvez essayer de convertir le code Python en C++ via ShedSkin (qui fonctionne pour la plupart du langage de base et certains modules de base, mais pas tous).

Néanmoins, vous pouvez suivre certains des conseils donnés ici :

http://wiki.python.org/moin/PythonSpeed/PerformanceTips

0 votes

Je ne suis ni un expert en perl ni un programmeur python. J'utilise perl et python d'après ce que j'ai lu dans un livre ordinaire de niveau débutant à intermédiaire. Si j'ai envie d'avoir de vraies performances, je vais certainement utiliser vos suggestions et même utiliser l'assemblage (si je l'apprends un jour). Utiliser ce qui est facilement disponible dans perl ou python et ses modules devrait être la seule suggestion que j'attends pour améliorer le code en termes de performances. Je ne m'attends pas à utiliser d'autres mots magiques à la mode et à prendre le temps d'apprendre le reste. Veuillez suggérer une solution pure qui existe dans l'installation python de nromal.

1 votes

Je comprends que tous les benchmarks artificiels peuvent être mauvais. Mais, le traitement de texte est simple et c'est ce que je fais normalement tous les jours. Donc, si python ne peut pas améliorer la vitesse d'utilisation de certaines syntaxes de base dans l'installation originale de python... (tout comme je le fais avec perl)... Je devrai recourir à perl pour mes tâches de traitement de texte... et pour traiter les 100 ou 100 000 fichiers que j'ai à traiter... et il faudra bien admettre que python est lent pour le simple traitement de texte tel que donné dans mon code. Mais, bon sang, je souhaite utiliser python pour sa syntaxe propre, mais avec un retard de vitesse... je ne le pense pas.

0 votes

Les expressions régulières en Python sont fournies par le module. Les expressions régulières en Perl ont une syntaxe intégrée et peuvent être compilées en tant qu'inlines (sans coût d'appel de fonction). Le traitement de texte n'a pas besoin d'être aussi simple. De toute façon, il faut utiliser le meilleur outil pour chaque tâche. Mon expérience personnelle est que les programmes Perl un peu plus complexes sont beaucoup plus difficiles à lire et à maintenir à l'avenir.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X