Shell-Script
並行化 Bash FOR 循環
我一直在嘗試使用 GNU Parallel 並行化以下腳本,特別是三個 FOR 循環實例中的每一個,但一直無法做到。FOR 循環中包含的 4 個命令串聯執行,每個循環大約需要 10 分鐘。
#!/bin/bash kar='KAR5' runList='run2 run3 run4' mkdir normFunc for run in $runList do fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat" fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear rm -f *.mat done
你為什麼不直接分叉(又名背景)它們?
foo () { local run=$1 fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat" fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear } for run in $runList; do foo "$run" & done
如果不清楚,重要的部分在這裡:
for run in $runList; do foo "$run" & done ^
導致函式在後台的分叉 shell 中執行。那是平行的。
範例任務
task(){ sleep 0.5; echo "$1"; }
連續執行
for thing in a b c d e f g; do task "$thing" done
並行執行
for thing in a b c d e f g; do task "$thing" & done
在 N 個程序批次中並行執行
N=4 ( for thing in a b c d e f g; do ((i=i%N)); ((i++==0)) && wait task "$thing" & done )
也可以將 FIFO 用作信號量並使用它們來確保盡快產生新程序並且同時執行不超過 N 個程序。但它需要更多的程式碼。
具有基於 FIFO 的信號量的 N 個程序:
# initialize a semaphore with a given number of tokens open_sem(){ mkfifo pipe-$$ exec 3<>pipe-$$ rm pipe-$$ local i=$1 for((;i>0;i--)); do printf %s 000 >&3 done } # run the given command asynchronously and pop/push tokens run_with_lock(){ local x # this read waits until there is something to read read -u 3 -n 3 x && ((0==x)) || exit $x ( ( "$@"; ) # push the return code of the command to the semaphore printf '%.3d' $? >&3 )& } N=4 open_sem $N for thing in {a..g}; do run_with_lock task $thing done
解釋:
printf
我們通過推送 (= ) 和彈出 (=read
) 標記 ( )將文件描述符 3 用作信號量'000'
。通過推送已執行任務的返回碼,如果出現問題,我們可以中止。