2017-04-12 132 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被髮明的原因。