目前,我有一个两列形式的大文本文件。我正在尝试打印唯一的第一列,并将其总和作为输出。
cat src
a 1
b 1
c 1
d 1
a 1
b 2
c 3
d 4
使用基本的awk,我可以实现所需的输出。
awk -F" " '{a[$1]+=$2;}END{for(i in a)print i" "a[i];}' src
a 2
b 3
c 4
d 5
手头的问题是,如果我们使用较大的输入文件运行该过程,则该过程将运行大量时间。因此,尝试使用gnu-parallel进行相同的操作并击中该位置。
cat src | parallel --pipe awk -F" " '{a[$1]+=$2;}END{for(i in a)print i" "a[i];}'
任何对此的指导将不胜感激。
答案 0 :(得分:2)
我发现GNU datamash是在这种情况下运行 独立 的最快工具。
测试文件(https://transfer.sh/hL5xL/file)的行数约为1200万,大小为116Mb。
这是长时间的效果统计信息:
$ du -sh inputfile
116M inputfile
$ wc -l inputfile
12520872 inputfile
$ time datamash -W -g1 sum 2 <inputfile > /dev/null
real 0m10.990s
user 0m10.388s
sys 0m0.216s
$ time awk '{ a[$1] += $2 }END{ for(i in a) print i, a[i] }' inputfile > /dev/null
real 0m12.361s
user 0m11.664s
sys 0m0.196s
$ time parallel -a inputfile --pipepart --block=11M -q awk '{ a[$1] += $2 }END{ for(i in a) print i, a[i] }' \
| awk '{ a[$1] += $2 }END{ for(i in a) print i, a[i] }' >/dev/null
real 0m8.660s
user 0m12.424s
sys 0m2.760s
对于 parallel 方法,请使用parallel
+ awk
的组合。
对于最新的datamash
版本,您可以尝试:
parallel -a inputfile --pipepart --block=11M datamash -sW -g1 sum 2 | datamash -sW -g1 sum 2
如您所见,GNU parallel
被用作最后一种方法,它由2 {awk
个命令的组合组成(一个用于汇总中间结果,另一个用于汇总最终结果)。
关键的GNU parallel
选项如下:
--pipepart
管道物理文件的一部分。--pipepart
的工作方式与--pipe
类似,但速度要快得多。
--block-size
大小
一次读取的块大小(以字节为单位)。
在测试案例中,我已将--block=11M
指定为主文件大小的〜10%。您可以将其调整为--block=100M
。
答案 1 :(得分:1)
我强烈怀疑awk
并不是问题。我已经生成了一个与您相似的测试文件,该文件有1亿行,大小约为1 GB。第一个字段中约有10万个唯一键。在我不太快的笔记本电脑上,您的awk
命令仅需一分钟即可运行。
在不了解您的计算机的情况下,我想问题可能是内存不足或I / O速度很慢。在我的系统上,awk
需要约512 MB的内存才能存储10万个密钥。如果您有数百万个键,则需要按比例增加内存,并且可能会发现内存不足导致交换的问题。交换对于散列数组和随机键确实非常不好。或者,如果您正在从速度较慢的网络文件系统或旧的USB存储器中读取文件,则可能只是在等待I / O,尽管这种可能性较小。
我建议您运行命令,然后用top
观看它,以查看发生了什么。您的awk
进程应使用100%的CPU。如果不是,top
应该显示交换或I / O等待问题。祝你好运。
答案 2 :(得分:0)
您说输入文件已排序,因此可以大大改善awk
命令:
awk -F" " '{if (key!=$1) {print key" "sum; key=$1; sum=0} sum+=$2}
END {print key" "sum}' inputfile
此命令使用固定数量的内存,而不是按键数量上的线性内存。与Jon suspected一样,您的情况可能是内存减慢的主要原因。
由于您的示例文件未排序,因此我们在sort
之后对管道中的命令进行测试
$ sort src | awk ...
a 2
b 3
c 4
d 5
可以通过在if
命令中添加另一个awk
或附加... | tail -n +2
来删除开头的其他空行。
如果未对输入文件进行排序,即使使用LC_ALL=C sort
进行排序速度更快,这种方法也会很慢(与sort
相比,它占用了系统时间的一半)。
请注意,这只是对awk
命令的改进。 datamash
command proposed by Roman还受益于已经排序的数据和节拍awk
。