1. 程式人生 > >shell高效處理文字(1):xargs並行處理

shell高效處理文字(1):xargs並行處理

xargs具有並行處理的能力,在處理大檔案時,如果應用得當,將大幅提升效率。

效率提升測試結果

先展示一下使用xargs並行處理提升的效率,稍後會解釋下面的結果。

測試環境:

  1. win10子系統上
  2. 32G記憶體
  3. 8核心cpu
  4. 測試物件是一個放在固態硬碟上行的10G文字檔案(如果你需要此測試檔案,點此下載,提取碼: semu)

下面是正常情況下wc -l統計這個10G檔案行數的結果,花費16秒,多次測試,cpu利用率基本低於80%

$ /usr/bin/time wc -l 9.txt
999999953 9.txt
4.56user 3.14system 0:16.06elapsed 47%CPU (0avgtext+0avgdata 740maxresident)k
0inputs+0outputs (0major+216minor)pagefaults 0swaps

通過分割檔案,使用xargs的並行處理功能進行統計,花費時間1.6秒,cpu利用率752%

$ /usr/bin/time ./b.sh
999999953
7.67user 4.54system 0:01.62elapsed 752%CPU (0avgtext+0avgdata 1680maxresident)k
0inputs+0outputs (0major+23200minor)pagefaults 0swaps

用grep從這個10G的文字檔案中篩選資料,花費時間24秒,cpu利用率36%

$ /usr/bin/time grep "10000" 9.txt >/dev/null
6.17user 2.57system 0:24.19elapsed 36%CPU (0avgtext+0avgdata 1080maxresident)k
0inputs+0outputs (0major+308minor)pagefaults 0swaps

通過分割檔案,使用xargs的並行處理功能進行統計,花費時間1.38秒,cpu利用率746%

$ /usr/bin/time ./a.sh
6.01user 4.34system 0:01.38elapsed 746%CPU (0avgtext+0avgdata 1360maxresident)k
0inputs+0outputs (0major+31941minor)pagefaults 0swaps

速度提高的不是一點點。

xargs並行處理簡單示例

要使用xargs的並行功能,只需使用"-P N"選項即可,其中N是指定要執行多少個並行程序,如果指定為0,則使用盡可能多的並行程序數量。

需要注意的是:

  • 既然要並行,那麼xargs必須得分批傳送管道的資料,xargs的分批選項有"-n"、"-i"、"-L",如果不知道這些內容,看本文開頭給出的文章。
  • 並行程序數量應該設定為cpu的核心數量。如果設定為0,在處理時間較長的情況下,很可能會併發幾百個甚至上千個程序。在我測試一個花費2分鐘的操作時,建立了500多個程序。
  • 在本文後面,還給出了其它幾個注意事項。

例如,一個簡單的sleep命令,在不使用"-P"的時候,預設是一個程序按批的先後進行處理:

[[email protected] ~]# time echo {1..4} | xargs -n 1 sleep
 
real    0m10.011s
user    0m0.000s
sys     0m0.011s

總共用了10秒,因為每批傳一個引數,第一批睡眠1秒,然後第二批睡眠2秒,依次類推,還有3秒、4秒,共1+2+3+4=10秒。

如果使用-P指定4個處理程序,它將以處理時間最長的為準:

[[email protected] ~]# time echo {1..4} | xargs -n 1 -P 4 sleep
 
real    0m4.005s
user    0m0.000s
sys     0m0.007s

再例如,find找到一大堆檔案,然後用grep去篩選:

find /path -name "*.log" | xargs -i grep "pattern" {}
find /path -name "*.log" | xargs -P 4 -i grep "pattern" {}

上面第一個語句,只有一個grep程序,一次處理一個檔案,每次只被其中一個cpu進行排程。也就是說,它無論如何,都只用到了一核cpu的運算能力,在極端情況下,cpu的利用率是100%。

上面第二個語句,開啟了4個並行程序,一次可以處理從管道傳來的4個檔案,在同一時刻這4個程序最多可以被4核不同的CPU進行排程,在極端情況下,cpu的利用率是400%。

並行處理示例

下面是文章開頭給出的實驗結果對應的示例。一個10G的文字檔案9.txt,這個檔案裡共有9.9億(具體的是999999953)行資料。

首先一個問題是,怎麼統計這麼近10億行資料的?wc -l,看看時間花費。

$ /usr/bin/time wc -l 9.txt
999999953 9.txt
4.56user 3.14system 0:16.06elapsed 47%CPU (0avgtext+0avgdata 740maxresident)k
0inputs+0outputs (0major+216minor)pagefaults 0swaps

總共花費了16.06秒,cpu利用率是47%

隨後,我把這10G資料用split切割成了100個小檔案,在提升效率方面,split切割也算是妙用無窮:

split -n l/100 -d -a 3 9.txt fs_

這100個檔案,每個105M,檔名都以"fs_"為字首:

$ ls -lh fs* | head -n 5
-rwxrwxrwx 1 root root 105M Oct  6 17:31 fs_000
-rwxrwxrwx 1 root root 105M Oct  6 17:31 fs_001
-rwxrwxrwx 1 root root 105M Oct  6 17:31 fs_002
-rwxrwxrwx 1 root root 105M Oct  6 17:31 fs_003
-rwxrwxrwx 1 root root 105M Oct  6 17:31 fs_004

然後,用xargs的並行處理來統計,以下是統計指令碼b.sh的內容:

#!/usr/bin/env bash

find /mnt/d/test -name "fs*" |\
 xargs -P 0 -i wc -l {} |\
 awk '{sum += $1}END{print sum}'

上面用-P 0選項指定了儘可能多地開啟併發程序數量,如果要保證最高效率,應當設定併發程序數量等於cpu的核心數量(在我的機器上,應該設定為8),因為在操作時間較久的情況下,可能會並行好幾百個程序,這些程序之間進行切換也會消耗不少資源。

然後,用這個指令碼去統計測試:

$ /usr/bin/time ./b.sh
999999953
7.67user 4.54system 0:01.62elapsed 752%CPU (0avgtext+0avgdata 1680maxresident)k
0inputs+0outputs (0major+23200minor)pagefaults 0swaps

花了1.62秒,cpu利用率752%。和前面單程序處理相比,時間是原來的16分之1,cpu利用率是原來的好多好多倍。

再來用grep從這個10G的文字檔案中篩選資料,例如篩選包含"10000"字串的行:

$ /usr/bin/time grep "10000" 9.txt >/dev/null
6.17user 2.57system 0:24.19elapsed 36%CPU (0avgtext+0avgdata 1080maxresident)k
0inputs+0outputs (0major+308minor)pagefaults 0swaps

24秒,cpu利用率36%

再次用xargs來處理,以下是指令碼:

#!/usr/bin/env bash

find /mnt/d/test -name "fs*" |\
 xargs -P 8 -i grep "10000" {} >/dev/null

測試結果:

$ /usr/bin/time ./a.sh
6.01user 4.34system 0:01.38elapsed 746%CPU (0avgtext+0avgdata 1360maxresident)k
0inputs+0outputs (0major+31941minor)pagefaults 0swaps

花費時間1.38秒,cpu利用率746%

這比用什麼ag、ack替代grep有效多了。

提升哪些效率以及注意事項

xargs並行處理用的好,能大幅提升效率,但這是有條件的。

首先要知道,xargs是如何提升效率的,以grep命令為例:

ls fs* | xargs -i -P 8 grep {}

之所以xargs能提高效率,是因為xargs可以分批傳遞管道左邊的結果給不同的併發程序,也就是說,xargs要高效,得有多個檔案可處理。對於上面的命令來說,ls可能輸出了100個檔名,然後1次傳遞8個檔案給8個不同的grep程序。

還有一些注意事項:

1.如果只有單核心cpu,像提高效率,沒門 2.xargs的高效來自於處理多個檔案,如果你只有一個大檔案,那麼需要將它切割成多個小片段 3.由於是多程序並行處理不同的檔案,所以命令的多行輸出結果中,順序可能會比較隨機

例如,統計行數時,每個檔案的出現順序是不受控制的。

10000000 /mnt/d/test/fs_002
9999999 /mnt/d/test/fs_001
10000000 /mnt/d/test/fs_000
10000000 /mnt/d/test/fs_004
9999999 /mnt/d/test/fs_005
9999999 /mnt/d/test/fs_003
10000000 /mnt/d/test/fs_006
9999999 /mnt/d/test/fs_007

不過大多數時候這都不是問題,將結果排序一下就行了。

4.xargs提升效率的本質是cpu的利用率,因此會有記憶體、磁碟速度的瓶頸。如果記憶體小,或者磁碟速度慢(將因為載入資料到記憶體而長時間處於io等待的睡眠狀態),xargs的並行處理基本無效

例如,將上面10G的文字檔案放在虛擬機器上,機械硬碟,記憶體2G,將會發現使用xargs並行和普通的命令處理幾乎沒有差別,因為絕大多數時間都花在了載入檔案到記憶體的io等待上。

下一篇文章將介紹GNU parallel並行處理工具,它的功能更豐富,效果更強大。