为什么使用管道进行排序(linux命令)很慢?

时间:2017-04-12 06:56:18

标签: linux sorting

我有一个大约8GB的大文本文件,我需要做一些简单的过滤然后对所有行进行排序。我使用的是具有SSD和128GB RAM的28核机器。我试过了

方法1

awk '...' myBigFile | sort --parallel = 56 > myBigFile.sorted

方法2

awk '...' myBigFile > myBigFile.tmp
sort --parallel 56 myBigFile.tmp > myBigFile.sorted

令人惊讶的是,方法1需要11.5分钟而方法2仅需要(0.75 + 1 <2)分钟。管道输出时为什么排序这么慢?这不是平行的吗?

修改

awkmyBigFile并不重要,只需使用seq 1 10000000 | sort --parallel 56(感谢@Sergei Kurenkov)就可以重复此实验,而且我还发现使用un可以提高六倍的速度在我的机器上的-piped版本。

3 个答案:

答案 0 :(得分:2)

从管道读取时,sort假定文件很小,而对于小文件,并行性没有帮助。要使sort使用并行性,您需要告诉它使用-S分配大型主内存缓冲区。在这种情况下,数据文件大约为8GB,因此您可以使用-S8G。但是,至少在具有128GB主内存的系统上,方法2可能仍然更快。

这是因为方法2中的sort可以从文件的大小知道它是巨大的,并且它可以在文件中查找(管道中都不可能)。此外,由于与这些文件大小相比,您拥有如此多的内存,因此myBigFile.tmp的数据无需在awk退出之前写入光盘,sort将能够从中读取文件缓存而不是光盘。所以方法1和方法2(在像你这样有大量内存的机器上)的主要区别在于方法2中的sort知道文件很大并且可以很容易地分割工作(可能使用搜索,但是我没有看过实现),而在方法1 sort必须发现数据是巨大的,并且它不能使用任何并行性来读取输入,因为它无法寻找管道。

答案 1 :(得分:1)

我认为从管道读取时sort不会使用线程。

  1. 我已经将此命令用于您的第一个案例。并且它表明sort仅使用1个CPU,即使它被告知使用4. atop实际上也表明sort中只有一个线程:

    /usr/bin/time -v bash -c "seq 1 1000000 | sort --parallel 4  > bf.txt"
    
  2. 我已将此命令用于第二种情况。它表明sort使用2个CPU。 atop实际上还显示sort中有四个帖子:

    /usr/bin/time -v bash -c "seq 1 1000000 > tmp.bf.txt && sort --parallel 4  tmp.bf.txt > bf.txt"
    
  3. 在第一个场景中,sort是一个I / O绑定任务,它从stdin执行大量read个系统调用。在第二个场景中,sort使用mmap系统调用来读取文件,避免成为I / O绑定任务。

    以下是第一和第二种情景的结果:

    $ /usr/bin/time -v bash -c "seq 1 10000000 | sort --parallel 4  > bf.txt"
            Command being timed: "bash -c seq 1 10000000 | sort --parallel 4  > bf.txt"
            User time (seconds): 35.85
            System time (seconds): 0.84
            Percent of CPU this job got: 98%
            Elapsed (wall clock) time (h:mm:ss or m:ss): 0:37.43
            Average shared text size (kbytes): 0
            Average unshared data size (kbytes): 0
            Average stack size (kbytes): 0
            Average total size (kbytes): 0
            Maximum resident set size (kbytes): 9320
            Average resident set size (kbytes): 0
            Major (requiring I/O) page faults: 0
            Minor (reclaiming a frame) page faults: 2899
            Voluntary context switches: 1920
            Involuntary context switches: 1323
            Swaps: 0
            File system inputs: 0
            File system outputs: 459136
            Socket messages sent: 0
            Socket messages received: 0
            Signals delivered: 0
            Page size (bytes): 4096
            Exit status: 0
    
    $ /usr/bin/time -v bash -c "seq 1 10000000 > tmp.bf.txt && sort --parallel 4  tmp.bf.txt > bf.txt"
            Command being timed: "bash -c seq 1 10000000 > tmp.bf.txt && sort --parallel 4  tmp.bf.txt > bf.txt"
            User time (seconds): 43.03
            System time (seconds): 0.85
            Percent of CPU this job got: 175%
            Elapsed (wall clock) time (h:mm:ss or m:ss): 0:24.97
            Average shared text size (kbytes): 0
            Average unshared data size (kbytes): 0
            Average stack size (kbytes): 0
            Average total size (kbytes): 0
            Maximum resident set size (kbytes): 1018004
            Average resident set size (kbytes): 0
            Major (requiring I/O) page faults: 0
            Minor (reclaiming a frame) page faults: 2445
            Voluntary context switches: 299
            Involuntary context switches: 4387
            Swaps: 0
            File system inputs: 0
            File system outputs: 308160
            Socket messages sent: 0
            Socket messages received: 0
            Signals delivered: 0
            Page size (bytes): 4096
            Exit status: 0
    

答案 2 :(得分:1)

如果使用管道,则有更多系统调用。

seq 1000000 | strace sort --parallel=56 2>&1 >/dev/null | grep read | wc -l
2059

如果没有管道,文件将被映射到内存中。

seq 1000000 > input
strace sort --parallel=56 input 2>&1 >/dev/null | grep read | wc -l
33

内核调用在大多数情况下都是瓶颈。这就是sendfile被发明的原因。

相关问题