我正在尝试对 7.6 GB gzip 文件进行记录计数。我发现使用该zcat
命令的方法很少。
$ zcat T.csv.gz | wc -l
423668947
这可行,但需要太多时间(超过 10 分钟才能得到计数)。我尝试了更多方法,例如
$ sed -n '$=' T.csv.gz
28173811
$ perl -lne 'END { print $. }' < T.csv.gz
28173811
$ awk 'END {print NR}' T.csv.gz
28173811
所有这三个命令的执行速度都非常快,但给出的计数不正确,为 28173811。
如何在最短的时间内执行记录计数?
答案1
您提到的sed
、perl
和awk
命令可能是正确的,但它们都读取压缩的数据并计算其中的换行符。这些换行符与未压缩数据中的换行符无关。
要计算未压缩数据中的行数,无法解压缩它。您的方法zcat
是正确的方法,并且由于数据如此之大,因此将要需要一些时间来解压它。
大多数处理gzip
压缩和解压缩的实用程序很可能会使用相同的共享库例程来执行此操作。加快速度的唯一方法是找到zlib
比默认例程更快的例程实现,并重建例如zcat
以使用它们。
答案2
使用 unpigz。
拘萨罗南达的回答是正确的,你将要需要解压缩整个文件才能扫描其内容。/bin/gunzip
在单核上尽可能快地完成此操作。猪猪gzip
是可以使用多个核心的并行实现。
遗憾的是,普通 gzip 文件的解压缩本身无法并行化,但确实提供了,pigz
的改进版本,它在单独的线程中执行相关工作,例如读取、写入和校验和。在一些快速基准测试中,几乎是我的 core i5 机器上的两倍。gunzip
unpigz
unpigz
gunzip
pigz
使用您最喜欢的包管理器进行安装,并使用unpigz
代替gunzip
,或unpigz -c
代替zcat
。所以你的命令变成:
$ unpigz -c T.csv.gz | wc -l
当然,所有这些都假设瓶颈是 CPU,而不是磁盘。
答案3
所有管道的问题在于,您基本上将工作量加倍。无论解压速度有多快,数据仍然需要穿梭到另一个进程。
Perl 有PerlIO::gzip它允许您直接读取 gzip 压缩的流。因此,即使它的解压速度可能不匹配,它也可能具有优势unpigz
:
#!/usr/bin/env perl
use strict;
use warnings;
use autouse Carp => 'croak';
use PerlIO::gzip;
@ARGV or croak "Need filename\n";
open my $in, '<:gzip', $ARGV[0]
or croak "Failed to open '$ARGV[0]': $!";
1 while <$in>;
print "$.\n";
close $in or croak "Failed to close '$ARGV[0]': $!";
我在旧电脑上尝试使用 13 MB gzip 压缩文件(解压至 1.4 GB)2010 款 MacBook Pro,配备 16 GB RAM和一个旧的ThinkPad T400 配备 8 GB RAM文件已在缓存中。在 Mac 上,Perl 脚本比使用管道要快得多(5 秒 vs 22 秒),但在 ArchLinux 上,它输给了 unpigz:
$ 时间 -p ./gzlc.pl 间谍.gz 1154737 真实 4.49 用户4.47 系统0.01
相对
$时间-p unpigz -c间谍.gz |厕所-l 1154737 真实3.68 用户4.10 系统1.46
和
$时间-p zcat间谍.gz |厕所-l 1154737 真实 6.41 用户6.08 系统0.86
显然,unpigz -c file.gz | wc -l
无论是在速度方面,使用都是赢家。而且,简单的命令行肯定胜过编写程序,无论程序多么短。
答案4
可以使用 zgrep
标志-c
和$
参数来完成。
在这种情况下, -c 指示命令输出匹配行数,并且正则表达式 $ 匹配行尾,因此它匹配每一行或文件。
zgrep -c $ T.csv.gz
正如 @StéphaneChazelas 所评论的 -zgrep
只是一个脚本zcat
,grep
它应该提供与最初建议类似的性能zcat | wc -l