2017-04-12 38 views
2

我有一个大的文本文件〜8GB,我需要做一些简单的过滤,然后对所有行进行排序。我在一台配备SSD和128GB RAM的28核机器上。我试图为什么使用pipe进行排序(linux命令)很慢?

方法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)分钟。管道排序时为什么排序很慢?它不是平行的吗?

EDIT

awkmyBigFile并不重要,这个实验是重复的通过简单地使用seq 1 10000000 | sort --parallel 56(感谢@Sergei Kurenkov),并且我还观察到使用未管道版本六倍速度的提高我的机器。

+1

尝试添加-S8G来分配一个8G缓冲区到管道的排序读数,看看是否有帮助。要一致地测量,你可能希望在每次运行之前(例如myBigFile在第一次读取之后缓存)[删除缓存](https://linux-mm.org/Drop_Caches),尽管这并不能解释这么大的差别。 –

+0

@JimD。这真的有帮助!现在比编写中间文件到SSD稍慢(134秒比105秒)(但不应该更快......?) – bbvan

+0

从管道读取时,排序不知道输入的时间长短。当从文件中读取时,它知道它有多大。除此之外,该文件缓存在128GB内存的系统上,因此排序实际上并不是从磁盘读取,而是从缓存中读取。所以我认为这种差异是由于知道投入是巨大的,并且有效地划分工作的效率,而管道中的排序必须发现输入是巨大的(即使没有-S 也不会这样做)。 –

回答

1

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

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

-2

AFIAK恕我直言,在你的第一种方法中,首先它将执行awk操作,然后将该操作转移到下一个排序命令,以便它在单个镜头内发生,并且awk的输出将作为排序的输入,因此绝对可以存储值(你的Input_file值)更多的内存将被采用,因为没有其他文件正在创建用于存储值(在awk操作之后awk中的那些值将存储在内存中,排序将仅从那里获取输入)。另一方面,在第二个命令中,正在创建一个正在被排序命令使用的新文件,因此内存不需要保留整个8 GB左右的文件,因此占用的内存会更少。

+0

我不确定内存的使用情况,但我怀疑128G或(128-8-8 = 112)G就足以对8GB文件进行排序 – bbvan

+0

我想我从未提及它会使用所有的内存,我说它会操作繁重,理由与我前面提到的相同。你可以平行检查内存使用的命令,如vmstat,top,htop,free等,并可以找出有多少内存正在被哪个工具等使用,并可以找出谁是操作系统级别的罪魁祸首。 – RavinderSingh13

+0

对不起,我误解了你。我以为你说这是慢的,因为它使用更多的内存(也许文件去交换)。 – bbvan

1

我认为从管道读取时排序不使用线程。

  1. 我在第一种情况下使用了这个命令。它表明sort只使用1个CPU,即使它被告知使用4 atop居然还表明,在sort只有一个线程:

    /usr/bin/time -v bash -c "seq 1 1000000 | sort --parallel 4 > bf.txt" 
    
  2. 我已经使用这个命令你的第二个案例。它表明这种排序使用2个CPU。 atop实际上也表明,有四个线程sort

    /usr/bin/time -v bash -c "seq 1 1000000 > tmp.bf.txt && sort --parallel 4 tmp.bf.txt > bf.txt" 
    

在你第一个方案的排序是I/O密集型任务,它确实很多从标准输入read系统调用。在第二种情况下,排序使用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 
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被发明的原因。