我们如何更快地使用unixsorting?

我们正在用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 
  1. 分而治之。 如果您首先对每个N文件进行排序(并在多处理器上使用不同的CPU),则N种文件的排序可能会更快。 然后,文件只需要合并(例如sort -m files ... ; -m是POSIX,应该有各种各样的支持;双关语意)。 排序每个文件消耗更少的资源。
  2. 排序一个快速/ tmp目录
  3. 在框外思考:使流程创建文件立即排序数据
  4. 暴力:投掷更多的硬件(内存,CPU周期)的问题:-)
  5. 了解外部排序的概念

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 ; awksed脚本中的^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文件),那么这根本就没有帮助。