2009-10-07 135 views
1

有没有比我的实际'zcat'解决方案用gunzip文件更快的解决方案?用Perl编写gunzip文件的最佳方法是什么?

小基准:

#!/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

看cpan.org - 这可能是一个模块来做到这一点。 – 2009-10-07 17:38:21

+3

@Paul:像IO :: Uncompress :: Gunzip? – 2009-10-07 17:45:16

+0

我在手机上写了评论,所以我没有办法查找和写出真实的答案,但听起来像是一个可能的候选人。 – 2009-10-07 18:21:09

回答

3

我按照runrig的建议更新了我的基准PerlIO::gzip

我更新的基准:

#!/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是最快的解决方案!

+0

不幸的是,PerlIO :: gzip没有打包在Debian中...... :( – sebthebert 2009-10-10 15:07:41

+0

这忽略了一个事实,即分叉的zcat可以(并且如果可用的话)使用第二个CPU核心,然后导致较低的挂钟时间。完全忽略实际的挂钟时间,并根据CPU时间总和(包括可能并行运行的子时间)计算s/iter和Rate,所以即使zcat在2个内核可用的情况下完成得更快,它也会声明perlio_gzip的速度更快。此外,600K的解压缩速度可能非常快,以至于初始开销在这里过重,请尝试更大的文件。 – mjy 2014-09-24 11:12:37

+0

这篇文章现在已经快7年了PerlIO :: gzip最近被Debian打包: $ sudo apt-安装libperlio-gzip-perl – JohnGH 2016-08-26 12:19:48

3

在典型的桌面硬件上,zcat几乎肯定会受到非重要数据上的I/O限制(您的示例文件极其微不足道,它们会被缓冲),其中cas e将不会有任何代码级别的优化功能适用于您。产生一个外部的gzip对我来说似乎很完美。

1

上次我尝试它时,产生一个外部的gunzip比使用Perl模块快很多(就像你的基准测试所示)。我怀疑这是所有涉及绑定文件句柄的方法调用。

由于类似原因,我预计<$z>$z->getline慢。在确定第一个需要被翻译成第二个时,有更多的魔法。

+1

如果你有多个内核,你可以有效地分离它们之间的工作。如果你使用一个库,它全部在同一个核心上。 – 2010-01-28 01:39:24

2

而且我也搞不懂为什么while (<$z>)while (my $line = $z->getline())慢...

因为$z是自绑对象,被捆物体是出了名的慢,<$z>使用捆绑对象接口请致电getline()而不是直接调用该方法。

你也可以尝试PerlIO-gzip但我怀疑它不会比其他模块快得多。

+0

+1回答我的第二个问题,但我更有兴趣回答我的第一个问题:) :) – sebthebert 2009-10-07 23:03:37

+0

实际上,PerlIO :: gzip似乎是最快的一个......真快! 我会尽快更新我的新问题! – sebthebert 2009-10-08 17:10:44

相关问题