我们正在用37个字段对5GB文件进行sorting,并用5个键进行sorting。 大文件由每个5MB的1000个文件组成。
190分钟后还没有完成。
我想知道是否有其他方法来加快sorting。 我们selectunixsorting是因为我们不希望它耗尽所有的内存,所以任何基于内存的方法都不行。
什么是独立sorting每个文件的优点,然后使用-m选项来合并sorting呢?
使用-S
其缓冲在内存中。 例如,要使用(最多)50%的内存作为排序缓冲区,请执行以下操作:
sort -S 50% file
请注意,现代Unix sort
可以并行排序。 我的经验是,它会自动使用尽可能多的核心。 您可以使用--parallel
直接设置它。 要使用4个线程进行排序:
sort --parallel=4 file
所以总而言之,你应该把所有东西放在一个文件中,并执行如下的操作:
sort -S 50% --parallel=4 file
sort -m files ...
; -m是POSIX,应该有各种各样的支持;双关语意)。 排序每个文件消耗更少的资源。 Unix的主要时间消费者之一是找到关键; 那只不过是你在简单的排序练习中看到的简单的比较操作罢了。 即使找到一个关键是一个相当缓慢的过程。
所以,加快速度的一种方法是通过对文件进行预处理,使得您提到的5个键位于每行的前面,然后对数据进行排序(可能使用拆分和合并他人建议的操作),然后删除密钥。
例如,如果您有冒号分隔的字段,并且排序键为1,3,7,10,12,并且它们都是常规字母排序,那么您可以使用:
awk -F: '{print "%s:%s:%s:%s:%s:%s\n", $1, $3, $7, $10, $12, $0; }' monster-file | sort -t: -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 | sed 's/^[^:]*:[^:]*:[^:]*:[^:]*:[^:]*://'
你甚至可以不用五个-k
选项,只需运行sort -t:
事实上,你可能会安排使用一个不同的分隔符(可能是一个控制字符,如^ A)来简化代码。 用这个替代字符将主要记录的关键字段分开:
awk -F: '{print "%s:%s:%s:%s:%s^A%s\n", $1, $3, $7, $10, $12, $0; }' monster-file | sort -t$'\001' | sed 's/^[^^A]*^A//'
这在$'\001'
参数中使用bash
-ism( ANSI-C引用 )进行sort
; awk
和sed
脚本中的^A
项是从输入Control-A中得到的 ,尽管您也可以安排bash
符号来提供该字符:
awk -F: '{print "%s:%s:%s:%s:%s'$'\001''%s\n", $1, $3, $7, $10, $12, $0; }' monster-file | sort -t$'\001' | sed "s/^[^$'\001']*$'\001'//"
( 警告:未经测试的脚本。 )
有一篇关于重新设计Unix排序(“建立工作分类例程的理论和实践”,JP Linderman,AT&T贝尔实验室技术杂志,1984年10月)的一篇引人入胜的文章,这篇文章并不容易找到(我还没有找到互联网尽管试图搜索它),这描述了/bin/sort
如何改进。 即使在所有的改进之后,其对复杂种类的建议之一也是如此。
Unix排序不是以任何方式最快的排序。 它使用一个奇怪的实现,可以很容易地超过数据集足够大,需要多个合并通行证,正如你明确做的那样。 我会看看替换。 您甚至可以考虑将文件加载到数据库中:您可能会以这种方式获得更好的性能,并且之后您肯定会获得更方便的数据。
为了完整性,主要问题是桶排序本身。 小数据集虽然不像Quicksort那么快,但它的运行速度是替换选择的两倍。 一旦进入多级合并,运行次数以及合并通道的数量完全支配CPU限制的分配阶段。
我在多年前为COBOL实现了一个排序合并包,直接从Knuth卷。 III,通过更换选择进行分配,并与虚拟运行平衡合并。 在足够大的数据集上,它很容易胜过Unix排序,随着N的增加,渐变越来越大,而“足够大”并不是那么大的磁盘大小。
将文件拆分成较小的文件,使用多个cpus对较小的文件进行排序,再合并到一起。
我曾经这样做过:
split -l5000000 data.tsv '_tmp'; ls -1 _tmp* | while read FILE; do sort $FILE -o $FILE & done; sort -m _tmp* -o data.tsv.sorted
它为我工作得很好。
20M行文件上的示例性能:
joshua10.13> wc randn20M.csv 20000000 20000000 163197726 randn20M.csv joshua10.14> cat par_srt.sh #!/bin/bash split -l5000000 randn20M.csv '_tmp'; ls -1 _tmp* | while read FILE; do sort $FILE -o $FILE & done; sort -m _tmp* -o data.tsv.sorted joshua10.15> time ./par_srt.sh 1.516u 0.344s 0:05.85 31.6% 0+0k 0+522584io 0pf+0w joshua10.16> time sort randn20M.csv -o dataone.sorted 21.461u 0.596s 0:24.08 91.5% 0+0k 0+318752io 0pf+0w
备注:如果你是I / O绑定的(例如20行的20g文件),那么这根本就没有帮助。