Thực sự muộn đến bữa tiệc ở đây, nhưng đây là giải pháp khác.
Rất nhiều giải pháp không xử lý dấu cách / ký tự đặc biệt trong các lệnh, không giữ cho N công việc chạy mọi lúc, ăn cpu trong các vòng lặp bận, hoặc dựa vào các phụ thuộc bên ngoài (ví dụ GNU parallel
).
Với nguồn cảm hứng cho việc xử lý quy trình chết / zombie , đây là một giải pháp bash thuần túy:
function run_parallel_jobs {
local concurrent_max=$1
local callback=$2
local cmds=("${@:3}")
local jobs=( )
while [[ "${#cmds[@]}" -gt 0 ]] || [[ "${#jobs[@]}" -gt 0 ]]; do
while [[ "${#jobs[@]}" -lt $concurrent_max ]] && [[ "${#cmds[@]}" -gt 0 ]]; do
local cmd="${cmds[0]}"
cmds=("${cmds[@]:1}")
bash -c "$cmd" &
jobs+=($!)
done
local job="${jobs[0]}"
jobs=("${jobs[@]:1}")
local state="$(ps -p $job -o state= 2>/dev/null)"
if [[ "$state" == "D" ]] || [[ "$state" == "Z" ]]; then
$callback $job
else
wait $job
$callback $job $?
fi
done
}
Và cách sử dụng mẫu:
function job_done {
if [[ $# -lt 2 ]]; then
echo "PID $1 died unexpectedly"
else
echo "PID $1 exited $2"
fi
}
cmds=( \
"echo 1; sleep 1; exit 1" \
"echo 2; sleep 2; exit 2" \
"echo 3; sleep 3; exit 3" \
"echo 4; sleep 4; exit 4" \
"echo 5; sleep 5; exit 5" \
)
cpus=3
run_parallel_jobs $cpus "job_done" "${cmds[@]}"
Đầu ra:
1
2
3
PID 56712 exited 1
4
PID 56713 exited 2
5
PID 56714 exited 3
PID 56720 exited 4
PID 56724 exited 5
Đối với mỗi quá trình xử lý đầu ra $$
có thể được sử dụng để đăng nhập vào một tệp, ví dụ:
function job_done {
cat "$1.log"
}
cmds=( \
"echo 1 \$\$ >\$\$.log" \
"echo 2 \$\$ >\$\$.log" \
)
run_parallel_jobs 2 "job_done" "${cmds[@]}"
Đầu ra:
1 56871
2 56872