題 並行shell循環


我想處理許多文件,因為我在這裡有一堆核心,我想並行執行:

for i in *.myfiles; do do_something $i `derived_params $i` other_params; done

我知道一個Makefile  但我的命令需要shell globbing列表中的參數。我發現的是:

> function pwait() {
>     while [ $(jobs -p | wc -l) -ge $1 ]; do
>         sleep 1
>     done
> }
>

要使用它,所有人必須做的就是在工作和一個pwait調用之後放置   參數給出了並行進程的數量:

> for i in *; do
>     do_something $i &
>     pwait 10
> done

但這不能很好地工作,例如我嘗試用​​它,例如一個for循環轉換許多文件,但給我錯誤和撤消作業。

我不能相信這還沒有完成,因為關於zsh郵件列表的討論現在已經很久了。所以你知道更好嗎?


10
2018-06-29 15:09


起源


與此問題類似: superuser.com/questions/153630/... 看看這種技術是否適合你。 - JRobert
如果您發布了錯誤消息,將會很有幫助。 - Dennis Williamson
@JRobert是的我知道這一點,但這實際上並沒有幫助,因為makefile方法不會像我說的那樣工作! @Dennis:好的,首先我在頂部旁邊顯示超過指定數量的進程。其次,它沒有正確返回提示。第三,我說它讓工作失敗是不對的:我只是放了一個指標 echo "DONE"在活動作業未完成之前執行的循環之後。 =>這讓我覺得工作沒有完成。 - math


答案:


一個makefile  一個很好的解決方案。你可以在shell中編寫這個並行執行程序,但是很難,正如你所注意到的那樣。 make的並行實現不僅會處理啟動作業並檢測它們的終止,還會處理負載平衡,這很棘手。

對globbing的要求不是障礙:有些make實現支持它。 GNU make,具有通配符擴展,如 $(wildcard *.c) 和shell訪問如 $(shell mycommand) (查看GNU make手冊中的函數以獲取更多信息)。這是默認值 make 在Linux上,並在大多數其他系統上可用。這是一個Makefile骨架,您可以根據自己的需要進行調整:

sources = $(通配符* .src)

all:$(來源:.src = .tgt)

%。tgt:$ .src
    do_something $ <$$(derived_pa​​rams $ <)> $ @

運行類似的東西 make -j4 並行執行四個作業,或 make -j -l3 將負載平均值保持在3左右。


14
2017-07-09 21:46





我不確定你的派生參數是什麼樣的。但是使用GNU Parallel http:// www.gnu.org/software/parallel/,你可以這樣做來為每個cpu核心運行一個作業:

find . | parallel -j+0 'a={}; name=${a##*/}; upper=$(echo "$name" | tr "[:lower:]" "[:upper:]");
   echo "$name - $upper"'

如果你想要得到的只是改變.extension,{。}可能很方便:

parallel -j+0 lame {} -o {.}.mp3 ::: *.wav

觀看介紹視頻到GNU Parallel at http://www.youtube.com/watch?v=OpaiGYxkSuQ


7
2017-07-27 09:37





不會使用shell wait 指揮為你工作?

for i in *
do
    do_something $i &
done
wait

你的循環執行一個作業,然後等待它,然後完成下一個工作。如果以上內容對您不起作用,那麼移動時您的工作效果會更好 pwait 後 done


6
2018-06-29 17:44



沒有100萬個文件我會運行100萬個進程,或者我錯了? - math
@brubelsabs:嗯,會的 嘗試 做一百萬個流程。您沒有在問題中說明需要處理多少文件。我認為你需要使用嵌套 for 循環以限制: for file in *; do for i in {1..10}; do do_something "$i" & done; wait; done (未經測試)這應該一次做十個並等到每組完成所有十個,然後再開始下一個十個。你的循環一次做一個 & 沒有實際意義。看到那個問題 JRobert 鏈接到其他選項。在Stack Overflow上搜索與您(和那個)類似的其他問題。 - Dennis Williamson
如果OP預計有一百萬個文件,那麼他就會遇到問題 for i in *。他必須用管道或其他東西將參數傳遞給循環。然後,您可以運行遞增計數器而不是內部循環 "micro-"wait"-s" 每個“$((i%32))” - eq'0'
@DennisWilliamson:結合 wait 內部計數器循環對我來說效果很好。謝謝! - Joel Purra


為什麼沒有人提到過xargs呢?

假設你有三個參數,

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; done | xargs -n 3 -P $PROCS do_something

否則使用分隔符(null很方便):

for i in *.myfiles; do echo -n $i `derived_params $i` other_params; echo -ne "\0"; done | xargs -0 -n 1 -P $PROCS do_something

編輯:對於上述情況,每個參數應該用空字符分隔,然後應該用xargs -n指定參數的數量。


3
2017-07-28 20:03



是的,在我們的項目中,有人有同樣的想法,即使在帶有MSys的Windows下也能正常工作。 - math