perlでgzipファイルを最速で読み込む方法
いくつか方法があるが、それぞれ試してみる。
サンプルファイル
環境
- OS
- Debian GNU/Linux 4.0 (coLinux 0.7.1)
- Perl
- v5.8.8
- メモリ
- 512MB/2048MB (coLinux割り当て/全体)
- PC
- HP ProLiant ML115 (Windows XP)
使うモジュール
- Compress-Zlib 2.008
- http://search.cpan.org/dist/Compress-Zlib/
- IO-Compress-Zlib 2.008
- http://search.cpan.org/dist/IO-Compress-Zlib/
- IO-Compress-Base 2.008
- http://search.cpan.org/dist/IO-Compress-Base/
- Compress-Raw-Zlib 2.008
- http://search.cpan.org/dist/Compress-Raw-Zlib/
計測用コードとか
一応測ったけどgzipにおまけでついてくるzcatは、gzip -cd と同じ性能。
そもそもバイナリも同じサイズ。
読み込みに使うファイルは上記の通り。最近はTSVしか使わないけど、手元にCSVがあったので流用。
結局あまりにでかいファイルは、普通は分割して処理するだろうしこのぐらいが無難じゃないかと。
100回ぐらいじゃ値が定まらないので1000回実行。
bench_gzip.pl
#!/usr/bin/perl use strict; use warnings; use Benchmark qw( :all ); use Compress::Zlib; use IO::File; my $file = 'sample.csv.gz'; my $file_plain = 'sample.csv'; print "warming up the file...\n"; system( "zcat $file > /dev/null" ); system( "gzip -cd $file > /dev/null" ); print "starting comparison...\n"; cmpthese( 1000, { 'uncompressed' => \&uncompressed, 'open_zcat' => \&open_zcat, 'fileio_zcat' => \&fileio_zcat, 'open_gzip' => \&open_gzip, 'fileio_gzip' => \&fileio_gzip, 'compress_zlib' => \&compress_zlib, }); print "\n"; sub uncompressed { open my $fh, '<', $file_plain or die "Can't open '$file_plain': $!"; my $lines = 0; while ( my $line = <$fh> ) { $lines++; } close $fh or die "Can't close '$file_plain' after reading: $!"; print "plain_open: $lines lines\n"; } sub open_zcat { open my $fh, "zcat $file 2>/dev/null |" or die "Can't zcat '$file' for reading: $!"; my $lines = 0; while ( my $line = <$fh> ) { $lines++; } close $fh or die "Can't close '$file_plain' after reading: $!"; print "open_zcat: $lines lines\n"; } sub fileio_zcat { my $fh = IO::File->new( "zcat $file 2>/dev/null |" ) or die "Can't zcat '$file' for reading: $!"; my $lines = 0; while ( defined(my $line = $fh->getline()) ) { $lines++; } $fh->close or die "Can't close '$file' after reading: $!"; print "fileio_zcat: $lines lines\n"; } sub open_gzip { open my $fh, "gzip -cd $file 2>/dev/null |" or die "Can't gzip -cd '$file' for reading: $!"; my $lines = 0; while ( my $line = <$fh> ) { $lines++; } close $fh or die "Can't close '$file_plain' after reading: $!"; print "open_gzip: $lines lines\n"; } sub fileio_gzip { my $fh = IO::File->new( "gzip -cd $file 2>/dev/null |" ) or die "Can't gzip -cd '$file' for reading: $!"; my $lines = 0; while ( defined(my $line = $fh->getline()) ) { $lines++; } $fh->close or die "Can't close '$file' after reading: $!"; print "fileio_gzip: $lines lines\n"; } sub compress_zlib { my $gz = gzopen( $file, 'rb' ) or die "Cant't gzopen '$file' for reading: $!"; my $line; my $lines = 0; while ( ( my $bytes = $gz->gzreadline( $line ) ) > 0 ) { die( $gz->gzerror ) if ( $bytes == -1 ); $lines++; } $gz->gzclose(); print "compress_zlib: $lines lines\n"; }
結果
Rate | compress_zlib | fileio_zcat | fileio_gzip | open_zcat | open_gzip | uncompressed | |
---|---|---|---|---|---|---|---|
compress_zlib | 5.40/s | -- | -84% | -85% | -91% | -91% | -95% |
fileio_zcat | 33.9/s | 527% | -- | -5% | -41% | -41% | -66% |
fileio_gzip | 35.8/s | 562% | 6% | -- | -38% | -38% | -64% |
open_zcat | 57.3/s | 961% | 69% | 60% | -- | -0% | -43% |
open_gzip | 57.3/s | 961% | 69% | 60% | 0% | -- | -43% |
uncompressed | 100/s | 1752% | 195% | 180% | 75% | 75% | -- |
非圧縮はこのぐらいのファイルサイズの差なら一番速い。
大きくなるにつれてたぶん差が縮まる。I/Oの差で圧縮してある方が速いこともあるかも。
Compress::Zlibは遅すぎ、ちょっとお話にならない。
IO::File使うと、openで処理するのと比べると倍ぐらい遅い。
ということで結論。普通にzcat(gzip -cd)の標準出力をパイプでopenするのが一番速い。
あっ!その場合、closeはいらないかも。