2009-10-07 10 views
1

Existe-t-il une solution plus rapide que ma véritable solution 'zcat' pour scinder des fichiers avec Perl?Quelle est la meilleure façon de gunzip fichiers avec Perl?

Un peu de référence:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Benchmark qw(cmpthese timethese); 
use IO::Uncompress::Gunzip qw(gunzip); 

my $re = qr/test/; 

my $bench = timethese($ARGV[1], { 

    zcat => sub { 
    if (defined open(my $FILE, "-|", "zcat " . $ARGV[0])) 
    { 
     while (<$FILE>) 
     { 
     print $_ if ($_ =~ $re); 
     } 
     close($FILE); 
    } 
    }, 

    io_gunzip => sub { 
    my $z = new IO::Uncompress::Gunzip $ARGV[0]; 
    while (<$z>) 
    { 
     print $_ if ($_ =~ $re); 
    } 
    }, 

    io_gunzip_getline => sub { 
    my $z = new IO::Uncompress::Gunzip $ARGV[0]; 
    while (my $line = $z->getline()) 
    { 
     print $line if ($line =~ $re); 
    } 
    }, 

}); 

cmpthese $bench; 

1; 

me donner ces résultats:

# zcat test.gz|wc -l 
566 
# zcat test2.gz|wc -l 
60459 

# ./zip_test.pl test.gz 500 
Benchmark: timing 500 iterations of io_gunzip, io_gunzip_getline, zcat... 
io_gunzip: 4 wallclock secs (3.01 usr + 0.01 sys = 3.02 CPU) @ 165.56/s (n=500) 
io_gunzip_getline: 3 wallclock secs (2.58 usr + 0.03 sys = 2.61 CPU) @ 191.57/s (n=500) 
     zcat: 2 wallclock secs (0.20 usr 0.34 sys + 0.55 cusr 1.10 csys = 2.19 CPU) @ 228.31/s (n=500) 
        Rate   io_gunzip io_gunzip_getline    zcat 
io_gunzip   166/s    --    -14%    -27% 
io_gunzip_getline 192/s    16%    --    -16% 
zcat    228/s    38%    19%    -- 

# ./zip_test.pl test2.gz 50 
Benchmark: timing 50 iterations of io_gunzip, io_gunzip_getline, zcat... 
io_gunzip: 31 wallclock secs (29.67 usr + 0.11 sys = 29.78 CPU) @ 1.68/s (n=50) 
io_gunzip_getline: 26 wallclock secs (24.86 usr + 0.04 sys = 24.90 CPU) @ 2.01/s (n=50) 
     zcat: 5 wallclock secs (2.42 usr 0.19 sys + 1.19 cusr 0.27 csys = 4.07 CPU) @ 12.29/s (n=50) 
        Rate   io_gunzip io_gunzip_getline    zcat 
io_gunzip   1.68/s    --    -16%    -86% 
io_gunzip_getline 2.01/s    20%    --    -84% 
zcat    12.3/s    632%    512%    -- 

Et je ne comprends pas pourquoi aussi "while (<$z>)" est plus lent que "while (my $line = $z->getline())" ...

+0

regardez sur cpan.org - il y a probablement un module pour cela. –

+3

@Paul: comme IO :: Uncompress :: Gunzip? –

+0

J'ai écrit ce commentaire sur mon téléphone portable, donc je n'avais pas les moyens de chercher et d'écrire une vraie réponse, mais cela semble être un candidat probable. –

Répondre

3

J'ai mis à jour mon banc d'essai avec PerlIO::gzip comme suggéré par runrig.

Mon référence mis à jour:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Benchmark qw(cmpthese timethese); 
use IO::Uncompress::Gunzip qw(gunzip); 
use PerlIO::gzip; 

my $re = qr/test/; 

my $bench = timethese($ARGV[1], { 

    zcat => sub { 
    if (defined open(my $FILE, "-|", "zcat " . $ARGV[0])) 
    { 
     while (<$FILE>) 
     { 
     print $_ if ($_ =~ $re); 
     } 
     close($FILE); 
    } 
    }, 

    io_gunzip => sub { 
    my $z = new IO::Uncompress::Gunzip $ARGV[0]; 
    while (<$z>) 
    { 
     print $_ if ($_ =~ $re); 
    } 
    }, 

    io_gunzip_getline => sub { 
    my $z = new IO::Uncompress::Gunzip $ARGV[0]; 
    while (my $line = $z->getline()) 
    { 
     print $line if ($line =~ $re); 
    } 
    }, 

    perlio_gzip => sub { 
    if (defined open(my $FILE, "<:gzip", $ARGV[0])) 
    { 
     while (<$FILE>) 
     { 
     print $_ if ($_ =~ $re); 
     } 
     close($FILE); 
    } 
    }, 

}); 

cmpthese $bench; 

1; 

Nouveaux résultats:

# zcat test.gz| wc -l 
566 
# zcat test2.gz| wc -l 
60459 
# zcat test3.gz| wc -l 
604590 
# ./zip_test.pl test.gz 1000 
Benchmark: timing 1000 iterations of io_gunzip, io_gunzip_getline, perlio_gzip, zcat... 
io_gunzip: 6 wallclock secs (6.07 usr + 0.03 sys = 6.10 CPU) @ 163.93/s (n=1000) 
io_gunzip_getline: 6 wallclock secs (5.23 usr + 0.02 sys = 5.25 CPU) @ 190.48/s (n=1000) 
perlio_gzip: 0 wallclock secs (0.62 usr + 0.01 sys = 0.63 CPU) @ 1587.30/s (n=1000) 
     zcat: 6 wallclock secs (0.37 usr 0.98 sys + 0.94 cusr 2.86 csys = 5.15 CPU) @ 194.17/s (n=1000) 
        Rate io_gunzip io_gunzip_getline   zcat perlio_gzip 
io_gunzip   164/s   --    -14%   -16%  -90% 
io_gunzip_getline 190/s   16%    --   -2%  -88% 
zcat    194/s   18%    2%   --  -88% 
perlio_gzip  1587/s   868%    733%   717%   -- 
# ./zip_test.pl test2.gz 50 
Benchmark: timing 50 iterations of io_gunzip, io_gunzip_getline, perlio_gzip, zcat... 
io_gunzip: 30 wallclock secs (29.50 usr + 0.11 sys = 29.61 CPU) @ 1.69/s (n=50) 
io_gunzip_getline: 25 wallclock secs (24.85 usr + 0.10 sys = 24.95 CPU) @ 2.00/s (n=50) 
perlio_gzip: 4 wallclock secs (3.22 usr + 0.01 sys = 3.23 CPU) @ 15.48/s (n=50) 
     zcat: 4 wallclock secs (2.35 usr 0.23 sys + 1.29 cusr 0.28 csys = 4.15 CPU) @ 12.05/s (n=50) 
        Rate io_gunzip io_gunzip_getline   zcat perlio_gzip 
io_gunzip   1.69/s   --    -16%   -86%  -89% 
io_gunzip_getline 2.00/s   19%    --   -83%  -87% 
zcat    12.0/s   613%    501%   --  -22% 
perlio_gzip  15.5/s   817%    672%   28%   -- 
# ./zip_test.pl test3.gz 50 
Benchmark: timing 50 iterations of io_gunzip, io_gunzip_getline, perlio_gzip, zcat... 
io_gunzip: 303 wallclock secs (299.28 usr + 1.30 sys = 300.58 CPU) @ 0.17/s (n=50) 
io_gunzip_getline: 250 wallclock secs (248.26 usr + 0.79 sys = 249.05 CPU) @ 0.20/s (n=50) 
perlio_gzip: 32 wallclock secs (32.03 usr + 0.20 sys = 32.23 CPU) @ 1.55/s (n=50) 
     zcat: 44 wallclock secs (24.64 usr 1.83 sys + 11.93 cusr 1.62 csys = 40.02 CPU) @ 1.25/s (n=50) 
        s/iter io_gunzip io_gunzip_getline   zcat perlio_gzip 
io_gunzip   6.01   --    -17%   -87%  -89% 
io_gunzip_getline 4.98   21%    --   -84%  -87% 
zcat    0.800   651%    522%   --  -19% 
perlio_gzip  0.645   833%    673%   24%   -- 

PerlIO::gzip est la solution la plus rapide!

+0

Malheureusement, PerlIO :: gzip n'est pas empaqueté dans Debian ... :( – sebthebert

+0

Cela ne tient pas compte du fait qu'un zcat forké peut (et utilisera, si disponible) un deuxième cœur de processeur, et donc des minuteries de wallclock inférieures. ignore complètement les horaires de wallclock réels et calcule s/iter et Rate à partir de la somme des temps processeur y compris les enfants (qui peuvent fonctionner en parallèle), donc même si zcat finit plus vite avec 2 cœurs disponibles, il réclamera que perlio_gzip est plus rapide m- (. .. Aussi, décompresser 600K est probablement si rapide que le surcoût initial pèse trop ici, essayez aussi des fichiers plus gros .. – mjy

+0

PerlIO :: gzip est maintenant empaqueté dans Debian ces jours: $ sudo apt- get install libperlio-gzip-perl – JohnGH

3

Sur un matériel de bureau typique, le zcat est presque certain d'être limité aux E/S sur des données non triviales (vos fichiers d'exemple sont terriblement triviaux, ils seront tamponnés à coup sûr), dans quel cas Il n'y aura pas d'optimisation au niveau du code qui fonctionnera pour vous. Frayer un gzip externe me semble parfait.

1

La dernière fois que je l'ai essayé, la génération d'un gunzip externe était considérablement plus rapide que l'utilisation d'un module Perl (comme le montrent vos tests). Je soupçonne que c'est tous les appels de méthode impliqués dans attacher un handle de fichier.

Je suppose <$z> est plus lent que $z->getline pour une raison similaire. Il y a plus de magie à comprendre que le premier doit être traduit dans le second.

+1

Si vous avez plusieurs cœurs, vous séparez effectivement le travail entre eux. Si vous utilisez une bibliothèque, tout est sur le même noyau. –

2

Et je ne comprends pas pourquoi while (<$z>) est plus lent que while (my $line = $z->getline()) ...

Parce que $z est un objet auto lié, les objets liés sont notoirement lents, et <$z> utilise l'interface objet lié à appelez getline() plutôt que d'appeler directement la méthode.

Aussi, vous pouvez essayer PerlIO-gzip mais je soupçonne qu'il ne sera pas beaucoup plus rapide que l'autre module.

+0

+1 pour répondre à ma deuxième question, mais je suis plus intéressé par les réponses à mon premier ... :) – sebthebert

+0

En fait, PerlIO :: gzip semble le plus rapide ... Vraiment plus rapide! Je vais mettre à jour ma question avec mon nouveau banc bientôt! – sebthebert

Questions connexes