我想在Linux中随机播放一个包含数百万行字符串的大文件。我尝试了 ' sort -R' 但它非常慢(对于16M大文件需要50分钟)。是否有更快的实用程序可以代替它使用?
答案 0 :(得分:26)
使用shuf
代替sort -R
(man page)。
sort -R
的缓慢是probably due to it hashing every line。 shuf
只是进行随机排列,因此它没有问题。
(这是在评论中提出的,但由于某种原因没有被任何人写成答案)
答案 1 :(得分:2)
根据您的描述,50分钟不是由实际排序机制引起的。时间可能花在等待/dev/random
上以产生足够的熵。
一种方法是使用外部随机数据源(例如http://random.org)以及Schwartzian Transform的变体。 Schwartzian变换将数据分类为“丰富”数据,并且嵌入了排序键。使用密钥对数据进行排序,然后丢弃密钥。
将此问题应用于您的问题:
生成一个随机数的文本文件,每行1个,行数与要排序的文件数相同。这可以在任何时候完成,在后台运行,在不同的服务器上运行,从random.org下载等。重点是在您尝试排序时不会生成此随机性。
使用paste
创建文件的丰富版本:
paste random_number_file.txt string_data.txt > tmp_string_data.txt
对此文件进行排序:
sort tmp_string_data.txt > sorted_tmp_string_data.txt
删除随机数据:
cut -f2- sorted_tmp_string_data.txt > random_string_data.txt
这是基本的想法。我尝试了它确实有效,但我没有1600万行文本或1600万行随机数。您可能希望管理其中一些步骤,而不是将其全部保存到磁盘。
答案 2 :(得分:-1)
您可以尝试我的工具:HugeFileProcessor。它能够在合理的时间内对数百GB的文件进行混洗。
以下是关于改组实施的详细信息。它需要指定 batchSize - 写入输出时保留在RAM中的行数。越多越好(除非你没有RAM),因为总的洗牌时间是(sourceFile中的行数)/ batchSize *(完全读取sourceFile的时间)。请注意,程序随机播放整个文件,而不是按批次。
算法如下。
计算 sourceFile 中的行数。这可以通过逐行读取整个文件来完成。 (参见一些比较here。)这也可以衡量一次读取整个文件需要多长时间。因此,我们可以估计完成一次shuffle需要多少次,因为它需要 Ceil(linesCount / batchSize)完整的文件读取。
我们现在知道 linesCount 的总数,我们可以创建 linesCount 大小的索引数组并使用Fisher–Yates对其进行随机播放(称为代码中的orderArray 。这将给我们一个订单,我们希望在洗牌文件中包含行。请注意,这是整个文件的全局顺序,而不是每批或块或其他内容。
现在是实际的代码。我们需要按照我们刚刚计算的顺序从 sourceFile 获取所有行,但是我们无法在内存中读取整个文件。所以我们只是拆分任务。
为什么会有效?
因为我们所做的只是从头到尾阅读源文件。没有寻求前进/后退,这就是硬盘驱动器所喜欢的。文件根据内部HDD缓冲区,FS块,CPU cahce等以块的形式读取,所有内容都按顺序读取。
有些数字
在我的机器上(Core i5,16GB RAM,Win8.1,HDD Toshiba DT01ACA200 2TB,NTFS)我可以使用 batchSize <在大约5小时内将132 GB(84 000 000行)的文件随机播放/ em>为3 500 000. batchSize 为2 000 000,耗时约8小时。读取速度约为每秒118000行。