IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Modules Perl Discussion :

Probleme performance, parametrage Tie::File


Sujet :

Modules Perl

  1. #1
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut Probleme performance, parametrage Tie::File
    Salut,
    J'ai une question à propos d'une modification de données dans un fichier via l'utilisation du module Tie::File et d'un parcours ligne à ligne.

    1 cas : Je travaille sur un fichier (importe l'extension) faisant 1,52 Mo
    - En utilisant le module Tie et en faisant à peu pres ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    tie my @lignes_fichier, 'Tie::File', $file 
            or croak("impossible d'ouvrir le fichier $file\n");
    foreach my $ligne (@lignes_fichier) {
                $ligne =~ s{$old_motif}{$new_motif}g;
            }
    untie @lignes_fichier;
    Il me met moins d'une seconde
    - En utilisant une configuration ligne à ligne en passant par un fichier temporaire via File::Temp et File::Copy pour recopier:
    il met 12 secondes
    N'est pas déjà trop long? y a t il plus simple à faire pour que ce soit plus rapide?

    Sinon tie est sans conteste plus performant dans ce cas

    2 cas : Je travaille sur un fichier (importe l'extension) faisant 37 Mo

    - via Tie, il met 12 min environ
    -via ligne à ligne + File::Temp + File::Copy => 3min 30 sec environ
    Je trouve que 32Mo c'est vraiment petit et ne comprends pourquoi c'est si long.
    Comment optimiser cela? De plus Tie est normalement bien fait pour gerer les gros fichiers, comment l'utiliser au mieux dans ce cas?

    NB: Mon PC a 1 Go de ram

    Merci

  2. #2
    Membre chevronné
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2003
    Messages
    1 572
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Industrie

    Informations forums :
    Inscription : Février 2003
    Messages : 1 572
    Points : 2 014
    Points
    2 014
    Par défaut
    Quand un modo pose une question sur Perl, j'évite de répondre, trop peur de dire une bêtise

    Bon allez, je me lance !!

    Tie Tie Tie.... Un rapport avec le Chasseur Tie ? Et/ou Jedai ?

    Sorry pour le HS, j'ai trouvé tout seul la sortie, hop là c'est par là ---> [ ]

  3. #3
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Citation Envoyé par Arioch
    Quand un modo pose une question sur Perl, j'évite de répondre, trop peur de dire une bêtise

    Bon allez, je me lance !!

    Tie Tie Tie.... Un rapport avec le Chasseur Tie ? Et/ou Jedai ?

    Sorry pour le HS, j'ai trouvé tout seul la sortie, hop là c'est par là ---> [ ]

  4. #4
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Cas 1 :

    Je vais hasarder une supposition : ta substitution ne se déclenche pas à toutes les lignes, et même elle ne se déclenche que vers la fin du fichier (ou du moins en majorité). Dans ce cas Tie::File est énormément gagnant : en effet il ne modifie qu'une partie du fichier (petite si les substitutions se font vers la fin du fichier)... tandis que l'autre approche recopie l'intégralité du fichier.
    Par ailleurs j'aimerais bien voir le code s'il est différent de celui que j'ai donné dans mon exemple : tu utilises bien File::Copy::move() et pas copy() ? D'autre part j'utilise File::Temp pour la sûreté de l'opération, mais ce n'est pas forcément le plus performant : par exemple tu peux être en train de modifier un fichier qui n'est pas sur le même système de fichier que ton répertoire temporaire (très courant sous Unix), et dans ce cas move() sera obligé de faire une copie plutôt qu'un rename() (un simple rename() échoue à franchir les frontières des systèmes de fichier), en fait si j'écrivais la chose avec à la fois la performance et la sécurité en tête, j'utiliserais File::Temp en lui spécifiant de créer le fichier temporaire dans le même répertoire que le fichier à modifier.

    1,52 Mo, c'est tout de même à peu près 16000 enregistrements (lignes) si ceux-ci font dans les 90 caractères. 16000 lecture de lignes, 16000 substitutions, etc... Ce n'est pas si simple de faire plus rapide, 1 seconde me parait très correct.

    Cas 2 :

    37 Mo pour un fichier texte, c'est déjà une taille assez monstrueuse (je suppose qu'on en croise fréquemment dans certaines situations cependant).

    Comment optimiser cela? De plus Tie est normalement bien fait pour gerer les gros fichiers, comment l'utiliser au mieux dans ce cas?
    Le problème est certainement qu'il y a des modifications nettement avant la fin du fichier... Dans ce cas Tie::File va recopier plusieurs fois de suite l'intégralité de la suite du fichier, qui est très longue !
    Pour éviter cela, il faut lui dire de travailler en mémoire : on commence par lui indiquer une taille maximale en mémoire (avec le paramètre "memory") plus importante, 30 Mo par exemple, puis on lui indique avec la méthode defer() (sur l'objet attaché, cf mon exemple et la variable $object) qu'on souhaite qu'il attende que les modifications lui prenne plus de place en mémoire que les 30 Mo spécifié avant de commencer à réellement modifier le fichier sous-jacent.

    Une autre piste d'optimisation peut être de travailler et de lire non plus ligne par ligne, mais gros bout de fichier par gros bout de fichier, si la logique de modification n'est pas par ligne (comme dans ton premier exemple : la substitution peut aussi bien être appliqué à l'ensemble du fichier en une seule passe, vu la taille de ce fichier, c'est d'ailleurs une option parfaitement viable), il y a de grande chance que ce soit bien plus rapide.

    --
    Jedaï

  5. #5
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Merci pour ta réponse jedai :

    CAS 1:
    - TIe
    en ce qui concerne le fichier, il fait donc 1, 5 Mo (c'est un fichier xml ). Il remplace un mot qui se retrouve dans toutes les balises (C'est juste pour faire des tests d'utilisation et du module Tie. donc par ligne il y a une modif
    Il fait 29814 lignes

    alors j'ai refait un test en utilisant les methode defer et flush systematiquement et en cas de fichier plus grand que 30 Mo (memory => 30_000_000 sinon memory => taille fichier).
    Donc c'est tres rapide (moins d'une demi seconde).

    - Ligne à ligne
    Je cree le fichier temporaire dans le repertoire ou se trouve le fichier à modifier.
    j'utilise File::copy et la methode copy. le fichier temporaire et de toute façon supprimer à la fin du script tout seul via l'option unlink du module FILE::Temp.
    rename ne fonctionne pas à cause de permission, mais de toute façon le temps ne se fait pas à se niveau mais bien pendant la lecture ligne à ligne.
    J'ai fait une barre de progression de progression histoire de voir le % au cours du parsing du fichier et quand je le desactive, bah on passe de 12 secondes à mions d'une seconde. donc le souci vien de là.
    au lieu de faire evolue la barre à chaque ligne, je le fait à chaque ligne modifié, donc c'est plus rapide s'il y a moins de modif. voilà, déjà un point de saisie et compris.

    CAS 2:
    fichier xml, 744000 lignes. Toutes les lignes ne sont pas à modifiers, mais je pourrais le tester.

    modif idem qu'au dessus.
    - Pour Tie, il ne met plus que
    *avec barre progress : toujours 12min
    * sans barre : 11 min 30

    - Ligne à ligne :
    *avec barre progress : (avec barre seulement sur ligne modifie) 50s
    * sans barre : 30 secondes

    donc en résumé, à partir d'une certaine taille de fichier, je ne sais pas laquelle, il est quand même preferable de faire du ligne à ligne.

    sinon qu'entends tu par gros bout de fichier?
    Scinder le fichier en plusieurs petit fichier par exemple et ensuite les traiter individuellement et les concatenainer?
    Si c'est ça, je vais essayer de faire une procedure pour tester.

  6. #6
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Citation Envoyé par djibril
    modif idem qu'au dessus.
    - Pour Tie, il ne met plus que
    *avec barre progress : toujours 12min
    * sans barre : 11 min 30
    Voilà qui me paraît assez étrange, même avec defer et une mémoire de 30 Mo c'est si lent que ça ? (EDIT : Un test de mon côté m'a donné des temps raisonnablement similaire : 3min à peu près pour 45 Mo)

    Citation Envoyé par djibril
    sinon qu'entends tu par gros bout de fichier?
    Scinder le fichier en plusieurs petit fichier par exemple et ensuite les traiter individuellement et les concatenainer?
    Si c'est ça, je vais essayer de faire une procedure pour tester.
    Je voulais dire que tu utilises effectivement la méthode de fichier temporaire, mais au lieu de lire ligne par ligne, tu lis par enregistrement de taille 2 Mo avec read() à la fois par exemple.

    --
    Jedaï

  7. #7
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    En effet 3 min, c'est déjà mieux, mais je ne sais pas pourquoi c different chez moi (peut etre memoire RAM , bizarre qd même)

    Sinon je me suis fais un petit moulinage creant repertoire temporaire et fichiers temporaires apres decoupe du fichier de 37 Mo en plusieurs fichier d'1 Mo.
    Ensuite j'utilise tie dessus avec progressbar et je reconcataine le tout et hop c ok en 1 min au lieu de 12

  8. #8
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    Bon bah je pense que la meilleure idée au cas ou le fichier serait gros (à chacun de definir une taille) est de couper le fichiers en plusieurs petits fichiers, de les traiter independamment puis de reconcatainer le tout.
    C'est ce que j'ai fais pour tout fichier plus gros que 2 Mo. Je les divise en fichier d'environ 1 Mo et voilà.
    Mon dernier test a été fait sur un fichier d'un 1Go 200 Mo. Et la modification a durée environ 35 min (win2000 1Go ram). Idem pour un fichier de 300Mo qui a duré 3 min (sur un windows vista 2Go Ram).

    Donc en fonction de la memoire de l'ordi et biensur de la regex pour le remplacement, ça peut etre encore plus rapide et dans mon cas en enlevant la barre de progression sur le fichier de 1 Go200Mo, on passe à 30min.

    Sinon jedai, je ne vois pas trop comment tester read? comment lire le fichier par bout de 2 Mo (par ex) via read sans au prealable mettre tout le fichier dans une variable?
    As tu un exemple de lecture d'un fichier via la fonction read!!

    Merci!

  9. #9
    Expert éminent
    Avatar de Jedai
    Homme Profil pro
    Enseignant
    Inscrit en
    Avril 2003
    Messages
    6 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Avril 2003
    Messages : 6 245
    Points : 8 586
    Points
    8 586
    Par défaut
    Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #!/usr/bin/env perl
    use strict;
    use warnings;
     
    my $filename = shift;
     
    open my ($file), '<', $filename
      or die "Can't open $filename : $!\n";
     
    my $size = 2 * 1024 * 1024;
    my $chunk;
    while ( read $file, $chunk, $size ) {
        $chunk =~ s/$/, et Bob était là/gm;
        print $chunk;
    }
     
    __END__
    --
    Jedaï

  10. #10
    Responsable Perl et Outils

    Avatar de djibril
    Homme Profil pro
    Inscrit en
    Avril 2004
    Messages
    19 820
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 19 820
    Points : 499 184
    Points
    499 184
    Par défaut
    merci jedai.


    Bon j'ai fait quelques batteries de tests :
    TIE => utiliser le module Tie::File avec memory => 20_000_000
    fichier de 37 Mo
    read() => utilisation de la fonction read() avec $size = 2_000_000
    ligne à ligne => lecture classique de fichier en perl

    read et ligne à ligne en utilisant aussi File::Temp et File::Copy
    Quand j'ai decouper les fichier, j'ai utiliser les barre de progression via Term:: ProgressBar
    Je me suis arrangé pour que la regex soit trouver sur plus de la moitie des ligne(fichier 1 et fichier 3), voir plusieurs fois par ligne (fichier 2).
    Je teste sous win2000 avec 1Go de RAM
    Je tiens à preciser que c'est juste une estimation et de plus l'utilisation de
    Term:: ProgressBar fait prendre beaucoup de secondes proportionnellement avec la taille du fichiers (Dans mes cas ou je decoupe les fichiers)

    Resumé :
    fichier 39.03 Mo
    -utilsation de TIE (sans decouper fichier en petit fichier de 2 Mo) => 6 min 47
    -utilsation de read(sans decouper fichier en petit fichier de 2 Mo) => 28 sec
    -ligne à ligne (sans decouper fichier en petit fichier de 2 Mo) => 32 sec

    -utilsation de TIE (en decoupant fichier en petit fichier de 2 Mo) => 1min 18
    -utilsation de read(en decoupant fichier en petit fichier de 2 Mo) => 1min 13
    -ligne à ligne (en decoupant fichier en petit fichier de 2 Mo) => 1min 18

    fichier 59.45 Mo
    -utilsation de TIE (sans decouper fichier en petit fichier de 2 Mo) => 29 min 47
    -utilsation de read(sans decouper fichier en petit fichier de 2 Mo) => 1min 42
    -ligne à ligne (sans decouper fichier en petit fichier de 2 Mo) => 57 sec

    -utilsation de TIE (en decoupant fichier en petit fichier de 2 Mo) => 1min 17
    -utilsation de read(en decoupant fichier en petit fichier de 2 Mo) => 1min 58
    -ligne à ligne (en decoupant fichier en petit fichier de 2 Mo) => 1min 55

    fichier 180 Mo
    -utilsation de TIE (sans decouper fichier en petit fichier de 2 Mo) => beaucoup
    -utilsation de read(sans decouper fichier en petit fichier de 2 Mo) => 3min 24
    -ligne à ligne (sans decouper fichier en petit fichier de 2 Mo) => 2min 28

    -utilsation de TIE (en decoupant fichier en petit fichier de 2 Mo) => 6min 50
    -utilsation de read(en decoupant fichier en petit fichier de 2 Mo) => 5min 49
    -ligne à ligne (en decoupant fichier en petit fichier de 2 Mo) => 6min 33

    Donc en resume, lecture ligne à ligne est le plus rapide pour la plus part des fichiers.
    et à la rigueur les deouper en plusieurs fichiers serait une bonne idée.

Discussions similaires

  1. [Flash 8] probleme de parametrage
    Par mael94420 dans le forum Flash
    Réponses: 3
    Dernier message: 31/05/2006, 07h50
  2. Tie::File
    Par Jedai dans le forum Modules
    Réponses: 1
    Dernier message: 25/03/2006, 18h46
  3. Probleme Performance Procedure stockee
    Par DaxTaz dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 16/09/2005, 18h43
  4. Probleme de perf avec File::Find::name;
    Par Ludo167 dans le forum Modules
    Réponses: 6
    Dernier message: 14/07/2004, 11h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo