awk vs perl在阅读csv?

chi*_*ori 1 perl awk

我在这里需要速度.我有一个500mb大小的csv文件(实际上有很多csv,但我现在只考虑一个)我需要阅读第3列并从中选择唯一的字符串.我测试了以下方法,我发现只有awk是最快的

使用perl:

  • 使用传统方式读取文件打开文件并将文件句柄传递给while循环
  • 取消设置$ /变量并将整个文件啜饮成字符串,然后拆分行并选择第3个字段并继续
  • 使用File :: Slurp模块
  • 使用Text :: CSV/XS来读取csv并做必要的事情

在上述所有方法中,解析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;
Run Code Online (Sandbox Code Playgroud)

另一个更新:发布并修复

我的csv被'|'分隔 我错过了引用它们.因此,执行时间显着减慢,而且它产生的输出是错误的,我没有注意到.引用分隔符后,脚本能够在大约18秒内完成,当我使用@Borodin逻辑限制字段分割时,执行时间进一步减少.我能达到与awk相同的速度.

我仍然发现Text :: CSV方法较慢,因为我的文件可以使用默认的分割方法,我将继续使用它.

Jon*_*ler 6

我生成了一个包含10,000,000行的350 MiB文件,类似于:

part1,part2,data856801,part4,part5
Run Code Online (Sandbox Code Playgroud)

(其中第三列中的数字是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
Run Code Online (Sandbox Code Playgroud)

这花了大约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
Run Code Online (Sandbox Code Playgroud)

这花了大约29秒,以未排序的顺序产生数据.GNU awk3.1.7花了大约15秒(令人印象深刻的更快).

只需使用catcp在文件上花费超过5秒钟.

所有过滤后的输出文件中都有899993行; 一致性很好.

因此,对于这项工作来说,Perl比awk我的机器稍慢,但不是50倍.我不确定在Perl脚本上可以进行多少优化; 我所写的内容非常简单粗暴.

测试:

  • MacBook Pro(2011年初),2.3 GHz Intel Core i7.
  • 16 GiB 1333 MHz DDR3 RAM.
  • 750 GiB 5400 rpm磁盘.
  • 小牛队10.9.2
  • Perl 5.18.1(5.16.2)
  • BSD awk20070501
  • GNU awk3.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;
Run Code Online (Sandbox Code Playgroud)

Perl跑得快

有趣的是,Borodin脚本花了大约17秒,比Perl-as- awkmode操作快了很多.知道Perl是否设法优化分割是很有趣的,因为它知道它只需要第三个字段,而awk模式必须在每一行中分割五个字段(对于样本文件),即使只使用了第三个字段.

这与GNU awk时间非常相似.