Quelle est la meilleure façon de les dézipper des fichiers avec Perl?
-
20-09-2019 - |
Question
Y at-il une solution plus rapide que ma solution 'zcat' réelle pour les dézipper des 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% --
Je ne comprends pas pourquoi « while (<$z>)
» est plus lent que « while (my $line = $z->getline())
» ...
La solution 2
Je mis à jour mon référence avec PerlIO :: gzip comme Runrig a suggéré.
Mon indice de 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;
De 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!
Autres conseils
Sur le matériel de bureau typique, le zcat est presque certain d'être d'E / S limité sur des données non trivial (vos exemples de fichiers sont terriblement trivial, ils vont être mises en mémoire tampon pour sûr), auquel cas il n'y aura pas être une optimisation au niveau du code qui fonctionnera pour vous. Frai un gzip externe me semble parfait.
Je ne comprends pas pourquoi
while (<$z>)
est plus lent quewhile (my $line = $z->getline())
...
Parce que $z
est un auto objet lié, les objets liés sont notoirement lents, et <$z>
utilise l'interface objet lié à appeler getline()
plutôt que d'appeler directement la méthode.
Vous pouvez également essayer PerlIO-gzip mais je pense que ce ne sera pas être une / beaucoup plus rapide que l'autre module.
La dernière fois que je l'ai essayé, fraye un gunzip
externe a été nettement plus rapide que d'utiliser un module Perl (comme vos repères montrent). Je soupçonne que ce sont tous les appels de méthode impliqués à lier un descripteur de fichier.
Je pense <$z>
est plus lent que $z->getline
pour une raison similaire. Il y a plus de magie impliquée dans déterminer que le premier doit être traduit dans la seconde.