我在这里需要速度。我有一个500mb大小的csv文件(实际上有很多csv,但我现在只考虑一个) 我需要阅读第3列并从中选择唯一的字符串。我测试过的以下方法,我发现只有awk是最快的
使用perl:
在上述所有方法中,解析csv大约需要500秒。
但如果我尝试使用awk做同样的事情,它会在近10秒内完成。
我仍在学习perl中的步骤,最近我对它的热情在看到它的哈希功能后增长了很多。但是这个问题占了我的位置 背部。这是unix工具占上风的perl的一些限制吗?
我知道Text :: CSV是处理csv文件的最佳方式。但速度是我关注的问题,我可以保证我的csv没有任何嵌入式逗号或其他问题,只有Text :: CSV可以处理。
更新:发现我的问题
my %hash;
my $file = $ARGV[0] or die "Need input CSV $!\n";
open(my $fh,'<',$file) or die "Could not open the $file $!\n";
while(my $line = <$fh>)
{
chomp($line);
my $field2=(split /|/, $line)[2]; #I missed to quote the pipe delimiter
$hash{$field2}++;
}
print "$_\n" for keys %hash;
另一个更新:发布并修复
我的csv由&#39; |&#39;分隔。我错过了引用它们。因此,执行时间显着减慢,而且它产生的输出是错误的,我没有注意到。引用分隔符后,脚本能够在大约18秒内完成,当我使用@Borodin逻辑限制字段分割时,执行时间进一步减少。我能达到与awk相同的速度。
我仍然发现Text :: CSV方法较慢,因为我的文件可以使用默认的分割方法,我将继续使用它。
答案 0 :(得分:6)
我生成了一个350 MiB文件,其10,000,000行类似于:
part1,part2,data856801,part4,part5
(其中第三列中的数字是100,000到999,999之间的随机值)并使用了自制的Perl 5.18.1:
time perl -n -a -F, -l -e '$a{$F[2]}++;
END { foreach $key (sort keys %a) {print "$key";} }' junk.data >junk.perl.output
这花了大约34秒。没有sort
,花了大约33秒(我在时间上有一些变化)。系统提供的Perl 5.16.2的时间基本相同。
为了比较,使用BSD awk
(20070501):
time awk -F, '{a[$3]++} END {for (key in a) print key}' junk.data > junk.awk.output
这花了大约29秒,以未排序的顺序产生数据。 GNU awk
3.1.7花了大约15秒(显着更快)。
只需在文件上使用cat
或cp
只需5秒钟。
所有过滤后的输出文件中都有899993行;一致性很好。
因此,对于这项工作来说,Perl似乎比awk
略慢,但在我的机器上不是50倍。我不确定在Perl脚本上可以进行多少优化;我所写的内容非常简单粗暴。
测试:
awk
20070501 awk
3.1.7 我让iTunes在后台播放音乐,并在浏览器中输入,因此在测试运行时系统没有闲置。
使用Text :: CSV with Text :: CSV_XS和以下脚本,花了将近49秒:
#!/usr/bin/env perl
use strict;
use warnings;
use Text::CSV;
my %a;
my $csv = Text::CSV->new ( { binary => 1 } ) # should set binary attribute.
or die "Cannot use CSV: ".Text::CSV->error_diag ();
open my $fh, "<:encoding(utf8)", "junk.data" or die "junk.data: $!";
while ( my $row = $csv->getline( $fh ) )
{
$a{$row->[2]}++;
}
$csv->eof or $csv->error_diag();
close $fh;
print "$_\n" for keys %a;
有趣的是,Borodin script大约需要17秒,比Perl-as - awk
模式操作快一点。知道Perl是否设法优化拆分会很有趣,因为它知道它只需要第三个字段,而awk
模式必须在每一行中拆分五个字段(对于样本文件),即使只有第三是使用。
这与GNU awk
时间非常相似。
答案 1 :(得分:3)
如果您显示了Perl代码,将会有所帮助。对于您描述的文件,不需要Text::CSV
的开销,其中数据从不包含逗号(并且可能没有引号?)
你的程序看起来应该是这样的
use strict;
use warnings;
use autodie;
open my $fh, '<', 'myfile';
my %data;
while (<$fh>) {
my $col3 = (split /,/, $_, 4)[2];
++$data{$col3};
}
print "$_\n" for keys %data;