我有一个大约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)分钟。管道输出时为什么排序这么慢?这不是平行的吗?
修改
awk
和myBigFile
并不重要,只需使用seq 1 10000000 | sort --parallel 56
(感谢@Sergei Kurenkov)就可以重复此实验,而且我还发现使用un可以提高六倍的速度在我的机器上的-piped版本。
答案 0 :(得分:2)
从管道读取时,sort
假定文件很小,而对于小文件,并行性没有帮助。要使sort
使用并行性,您需要告诉它使用-S
分配大型主内存缓冲区。在这种情况下,数据文件大约为8GB,因此您可以使用-S8G
。但是,至少在具有128GB主内存的系统上,方法2可能仍然更快。
这是因为方法2中的sort
可以从文件的大小知道它是巨大的,并且它可以在文件中查找(管道中都不可能)。此外,由于与这些文件大小相比,您拥有如此多的内存,因此myBigFile.tmp
的数据无需在awk
退出之前写入光盘,sort
将能够从中读取文件缓存而不是光盘。所以方法1和方法2(在像你这样有大量内存的机器上)的主要区别在于方法2中的sort
知道文件很大并且可以很容易地分割工作(可能使用搜索,但是我没有看过实现),而在方法1 sort
必须发现数据是巨大的,并且它不能使用任何并行性来读取输入,因为它无法寻找管道。
答案 1 :(得分:1)
我认为从管道读取时sort不会使用线程。
我已经将此命令用于您的第一个案例。并且它表明sort
仅使用1个CPU,即使它被告知使用4. atop
实际上也表明sort
中只有一个线程:
/usr/bin/time -v bash -c "seq 1 1000000 | sort --parallel 4 > bf.txt"
我已将此命令用于第二种情况。它表明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"
在第一个场景中,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被发明的原因。