天天看點

15分鐘入門parallel

GNU Parallel是一個Linux下的工具,為了在一台或多台計算機上并行的執行計算任務,一個計算任務可以是一條shell指令或者一個以每一行做為輸入的腳本程式。通常的輸入是檔案清單、主機清單、使用者清單、URL清單或者表格清單;一個計算任務也可以是一個從管道讀取的一條指令。GNU Parallel會把輸入分塊,然後通過管道并行的執行。

如果你會使用xargs和tee指令,你會發現GNU Parallel非常易于使用,因為GNU Parallel具有與xargs一樣的選項。GNU Parallel可以替代大部分的shell循環,并且用并行的方式更快的完成計算任務。

GNU Parallel保證它的輸出與順序執行計算任務時是一樣的,這樣就可以友善的把GNU Parallel的輸出做為其它程式的輸入。

對于每一行輸入,GNU Parallel會把這一行做為參數來運作指定的指令。如果沒有給出指令,那麼這一行會被當做指令執行。多行輸入會并行的運作。GNU Parallel經常被用于替代xargs或者cat | bash。

                                                                                                                                                                                                                                                         ---引用自某網絡文章                      

2.1 入門小例子

下面是一個小例子,幫助你了解Parallel的威力:

假設你已經知道seq指令的用途,在linux執行seq 5,會得到如下結果:

root@i-s0tsk03r:~# seq 5

1

2

3

4

5

試下執行seq 5 | parallel seq {} '>' example.{},這條指令相當于:

seq 1 > example.1

seq 2 > example.2

seq 3 > example.3

seq 4 > example.4

seq 5 > example.5

seq 5生成了一個清單,包含“1,2,3,4,5”這五個元素,通過管道符"|"傳遞給Parrallel,Parrallel中的‘{}’類似于占位符,是以就變成了上述代碼塊中的五行代碼,這裡有個小技巧,使用--dry-run選項可以列印出來Parrallel實際執行的指令:seq 5 | parallel --dry-run seq {} '>' example.{}

2.2 輸入源

GNU Parallel從輸入源中讀取資料,每個輸入源都是一個指令行,輸入源跟着‘:::’這個符号後面:

parallel echo ::: 1 2 3 4 5

指令結果:(順序可能和實際有所不同)

如果程式的輸入源是一些檔案的時候,那麼這個時候使用Parallel将非常便捷,例如:

parallel wc ::: example.*

根據上面入門小例子生成的五個檔案(example.1,example.2,example.3,example.4,example.5),使用--dry-run選項,實際執行的應該是如下指令:

wc example.1

wc example.2

wc example.3

wc example.4

wc example.5

      程式運作結果是

1 1 2 example.1

2 2 4 example.2

3 3 6 example.3

4 4 8 example.4

5  5 10 example.5

      如果你使用了多個:::,GNU Parallel将生成所有輸入源的組合

parallel echo ::: S M L ::: Green Red

      同樣的,我們使用--dry-run指令看看實際執行的是什麼

echo S Green

echo S Red

echo M Green

echo M Red

echo L Green

echo L Red

結果當然會輸出六行,相當于輸入源3*2=6

Parallel也支援從标準輸入讀入,類似最開始seq的例子,下面是一個新的例子:

find example.* | parallel echo File

我們使用--dry-run指令看看實際執行的是什麼

echo File example.1

echo File example.2

echo File example.3

echo File example.4

echo File example.5

        這個指令其實相當于:

parallel echo File ::: example.*

2.3 建構指令行

        Shell指令是在:::之前的,我們可以為為指令行添加指令行選項:

parallel wc -l :: example.*

在這裡我們為wc指定了選項-l,輸出結果為(順序可能和實際有所不同):

1 example.1

2 example.2

3 example.3

4 example.4

5 example.5

上述的指令裡面可以包含多條Shell指令(或者多個程式),隻要保證每條指令之間用";"分割開來即可(shell的文法,多個指令或者程式寫在一行需要用“;”分割)

執行:parallel --dry-run echo counting lines';' wc -l ::: example.*

echo counting lines; wc -l example.1

echo counting lines; wc -l example.2

echo counting lines; wc -l example.3

echo counting lines; wc -l example.4

echo counting lines; wc -l example.5

輸出結果為(順序可能和實際有所不同):

counting lines

輸入源的值通常附加到指令後面,通過使用{},我們可以在任意地方把輸入源的值替換到{}:

parallel  --dry-run echo counting {}';' wc -l {} ::: example.*

實際的指令如下:

echo counting example.1; wc -l example.1

echo counting example.2; wc -l example.2

echo counting example.3; wc -l example.3

echo counting example.4; wc -l example.4

echo counting example.5; wc -l example.5

      {}替換了example.*中的每個值,實際上{}隻适用于隻有一個:::的情況,如果有多個:::,我們可以分别使用{1},{2}...{n}來替代每個:::後的輸入源,下面是一個例子:

parallel --dry-run echo count {1} in {2}';' wc {1} {2} ::: -l -c ::: example.*

#這個例子比較複雜,我們需要用dry-run看看實際到底執行了什麼,實際執行的指令如下:

echo count -l in example.1; wc -l example.1

echo count -l in example.2; wc -l example.2

echo count -l in example.3; wc -l example.3

echo count -l in example.4; wc -l example.4

echo count -l in example.5; wc -l example.5

echo count -c in example.1; wc -c example.1

echo count -c in example.2; wc -c example.2

echo count -c in example.3; wc -c example.3

echo count -c in example.4; wc -c example.4

echo count -c in example.5; wc -c example.5

先看下輸入源:

第一個輸入源:::對應的是-l -c

第二個輸入源:::對應的是example.*

      是以{1}代表的是{-l  -c}這個集合,{2}代表的是{example.1 example.2 example.3 example.4 example.5}這個集合,然後根據組合2*5=10,一共生成了如上的十個指令。

      看到這裡,如果你考慮用parallel去改造你之前的shell中的循環,那應該是一個相當棒的主意!

2.4 輸出控制

      Parallel的輸出會随着所有指令結束而被立即列印出來,這就意味着輸出的順序可能和輸入的順序不完全相同,例如:

parallel sleep {}';' echo {} done ::: 5 4 3 2 1

#這個指令一眼看上去結果應該是

5 done

4 done

3 done

2 done

1 done

#但是實際可能是

原因是什麼呢,可能是因為sleep的時候,多程序切換的順序是不固定的,如果我們想要強制有序輸出,那麼可以指定參數--keep-order/-k,這樣得到的結果就會是有序的,例

parallel -k sleep {}';' echo {} done ::: 5 4 3 2 1

輸出結果為(結果順序一定是預期的):

2.5 執行控制

如果你的任務是計算密集型的,Parallel将幫助你在每個CPU上運作一個任務,達到并行的效果。

但是有時候你希望能夠運作更多的任務,你可以通過-j/--jobs選項控制任務槽(執行任務的單元)。為parallel裡面指定--jobs參數,這裡我們可以指定parallel運作槽為2:

parallel --jobs 2 sleep {}';' echo "jobs:" {%} 'echo' {} done ::: 5 4 3 1 2

jobs: 2 echo 4 done

jobs: 1 echo 5 done

jobs: 1 echo 1 done

jobs: 2 echo 3 done

jobs: 1 echo 2 done

兩個job的槽會花1~5分鐘來完成這五個任務的處理。在這裡,我們使用了{%}來列印job的id(類似于程序id)。可以看到五個輸入被分為如下的序列:

Job slot 1:5 1 2

Job slot 2:4 3

當然了,你可以通過指定'--job 5'讓五個任務并行起來,這樣所有的五個任務會同時啟動,但是它們會在不同時刻結束。

parallel --jobs 5 sleep {}';' echo "jobs:" {%} 'echo' {} done ::: 5 4 3 1 2

輸出

jobs: 4 echo 1 done

jobs: 5 echo 2 done

jobs: 3 echo 3 done

所有的任務都是并行運作的:

Job slot 1:5

Job slot 2:4

Job slot 3:3

Job slot 4:1

Job slot 5:2

你可以傳遞'--job 0'來盡量讓任務跑滿所有CPU,而不是手動指定job的number,這樣效率會更高。

2.6 管道模式

Parallel可以通過标準輸入傳遞資料塊給指令行:

seq 1000000 | parallel --pipe wc

#這裡比較疑惑地方是加--pipe和不加該選項有什麼差別呢?

#seq 1000000 | wc,相當于生成了一個資料塊,通過标準輸入給了wc,是以結果應該是

1000000 1000000 6888896

#wc指令會列印出行數,字元數,位元組數,拿seq 11舉例子,輸出應該是

6

7

8

9

10

11

#那麼,seq 11 | wc ,應該是11,11,24,第一個11代表有11行,第二個11代表有11個字元,第三個24相當于(1到9,10拆分成1和0,11拆分成1和1,然後一共附加11個換行符)

#如果不加--pipe呢,seq 100000 | parallel  wc會報錯,此時找不到wc 1到wc 100000這些指令

seq 1000000 | parallel --pipe wc的輸出(順序可能和實際有所不同):

165668  165668 1048571

149796  149796 1048572

  85352  85352  597465

這樣相當于parallel内部對資料塊進行了切開,然後并行多個wc去處理一小塊資料,沒有寫代碼就輕松實作了并行的大資料檔案處理,是不是很神奇!

Tips:GNU Parallel會對大資料塊以'\n'進行拆分(即加一個換行符),拆分後的每個部分大小不會超過1MB,是以對于大資料塊的程式處理機器有幫助。

2.7 小結

相信你已經掌握了GNU Parallel的基本使用方法,在大部分的場景下,可能已經夠用了。

剩下的部分會讨論更多Parallel的使用細節,覆寫更多的使用場景。

個人聲明:本文翻譯源于GNU Parallel 2018官方文檔,很多地方加入了自己的了解,由于翻譯水準有限,可能存有勘誤。如果有涉及到版權問題,請直接郵件與我聯系:[email protected]

 部落客:測試生财(一個不為996而996的測開碼農)

座右銘:專注測試開發與自動化運維,努力讀書思考寫作,為内卷的人生奠定财務自由。

内容範疇:技術提升,職場雜談,事業發展,閱讀寫作,投資理财,健康人生。

csdn:https://blog.csdn.net/ccgshigao

部落格園:https://www.cnblogs.com/qa-freeroad/

51cto:https://blog.51cto.com/14900374

微信公衆号:測試生财(定期分享獨家内容和資源)

15分鐘入門parallel

繼續閱讀