在Linux中对文件中的行进行随机播放的最快方法

时间:2013-02-06 10:48:57

标签: linux bash unix

我想在Linux中随机播放一个包含数百万行字符串的大文件。我尝试了 ' sort -R' 但它非常慢(对于16M大文件需要50分钟)。是否有更快的实用程序可以代替它使用?

3 个答案:

答案 0 :(得分:26)

使用shuf代替sort -Rman page)。

sort -R的缓慢是probably due to it hashing every lineshuf只是进行随机排列,因此它没有问题。

(这是在评论中提出的,但由于某种原因没有被任何人写成答案)

答案 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的时间)。请注意,程序随机播放整个文件,而不是按批次。

算法如下。

  1. 计算 sourceFile 中的行数。这可以通过逐行读取整个文件来完成。 (参见一些比较here。)这也可以衡量一次读取整个文件需要多长时间。因此,我们可以估计完成一次shuffle需要多少次,因为它需要 Ceil(linesCount / batchSize)完整的文件读取。

  2. 我们现在知道 linesCount 的总数,我们可以创建 linesCount 大小的索引数组并使用Fisher–Yates对其进行随机播放(称为代码中的orderArray 。这将给我们一个订单,我们希望在洗牌文件中包含行。请注意,这是整个文件的全局顺序,而不是每批或块或其他内容。

  3. 现在是实际的代码。我们需要按照我们刚刚计算的顺序从 sourceFile 获取所有行,但是我们无法在内存中读取整个文件。所以我们只是拆分任务。

    • 我们将通过 sourceFile 读取所有行,并在内存中仅存储 orderArray 的第一个 batchSize 中的那些行。当我们获得所有这些行时,我们可以按要求的顺序将它们写入 outFile ,并且它是 batchSize / linesCount 完成的工作。
    • 接下来,我们将一遍又一遍地重复整个过程,然后再从 orderArray 的下一部分开始,并从头到尾为每个部分读取 sourceFile 。最终整个 orderArray 得到处理,我们就完成了。
  4. 为什么会有效?

    因为我们所做的只是从头到尾阅读源文件。没有寻求前进/后退,这就是硬盘驱动器所喜欢的。文件根据内部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行。