我的目錄中有一堆 PNG 圖像。我有一個名為 pngout 的應用程序,我運行它來壓縮這些圖像。該應用程式由我編寫的腳本呼叫。問題是這個腳本一次執行一個操作,如下圖:
FILES=(./*.png)
for f in "${FILES[@]}"
do
echo "Processing $f file..."
# take action on each file. $f store current file name
./pngout -s0 $f R${f/\.\//}
done
一次只處理一個文件需要花費大量時間。運行這個應用程式後,我發現 CPU 只有 10%。所以我發現我可以將這些檔案分成4 個批次,將每個批次放入一個目錄中,然後從四個終端視窗、四個進程中觸發4 個,因此我的腳本有四個實例,同時處理這些圖像和工作佔用了1/4的時間。
第二個問題是我浪費了時間分割圖像和批次並將腳本複製到四個目錄,打開4個終端窗口,等等...
如何用一個腳本來實現這一點,而無需分割任何東西?
我的意思是兩件事:首先,如何從 bash 腳本將進程啟動到後台? (只需在末尾添加 & 即可?) 第二:發送第四個任務後如何停止向後台發送任務並讓腳本等待任務結束?我的意思是,只是在一個任務結束時向後台發送一個新任務,始終保持 4 個任務並行?如果我不這樣做,循環將向後台發送無數的任務,並且 CPU 將堵塞。
答案1
xargs
如果您有支援並行執行的副本-P
,您可以簡單地執行
printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}
對於其他想法,Wooledge Bash wiki 有一個部分在流程管理文章中準確描述了您想要的內容。
答案2
除了已經提出的解決方案之外,您還可以建立一個 makefile,描述如何從未壓縮檔案產生壓縮文件,並用於make -j 4
並行運行 4 個作業。問題是您需要以不同的方式命名壓縮文件和未壓縮文件,或者將它們存儲在不同的目錄中,否則編寫合理的 make 規則將是不可能的。
答案3
如果您有 GNU Parallelhttp://www.gnu.org/software/parallel/安裝後你可以這樣做:
parallel ./pngout -s0 {} R{} ::: *.png
您可以簡單地透過以下方式安裝 GNU Parallel:
wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
觀看 GNU Parallel 的介紹影片以了解更多資訊: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
答案4
回答你的兩個問題:
- 是的,在行尾新增 & 將指示您 shell 啟動背景進程。
- 使用該
wait
命令,您可以要求 shell 等待後台的所有進程完成,然後再繼續。
這是修改後的腳本,j
用於追蹤後台進程的數量。當NB_CONCURRENT_PROCESSES
達到該值時,腳本將重設為j
0 並等待所有後台程序完成,然後再恢復執行。
files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
echo "Processing $f file..."
# take action on each file. $f store current file name
./pngout -s0 "$f" R"${f/\.\//}" &
((++j == nb_concurrent_processes)) && { j=0; wait; }
done