是否有比使用Perl的gunzip文件的实际'zcat'解决方案更快的解决方案?
一个小基准:
#!/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;
给我这些结果:
# 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% --
我也不明白为什么“while (<$z>)
”比“while (my $line = $z->getline())
”慢......
答案 0 :(得分:3)
在典型的桌面硬件上,zcat几乎肯定会受到非平凡数据上的I / O限制(你的示例文件非常简单,它们肯定会被缓冲),在这种情况下不会是适合您的任何代码级优化。产生外部gzip对我来说似乎很完美。
答案 1 :(得分:3)
我使用PerlIO::gzip更新了我的基准,如runrig建议的那样。
我的更新基准:
#!/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;
新结果:
# 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是最快的解决方案!
答案 2 :(得分:2)
我也不明白为什么
while (<$z>)
慢于while (my $line = $z->getline())
...
因为$z
是一个自绑定对象,所以绑定对象非常慢,<$z>
使用绑定对象接口来调用getline()
而不是直接调用该方法。
你也可以尝试PerlIO-gzip,但我怀疑它不会比其他模块更快/更快。
答案 3 :(得分:1)
我最后一次尝试它时,产生一个外部gunzip
比使用Perl模块要快得多(就像你的基准测试一样)。我怀疑这是绑定文件句柄所涉及的所有方法调用。
由于类似原因,我预计<$z>
比$z->getline
慢。在确定第一个需要转化为第二个时,还有更多的魔力。