在Bash循环中使用wait命令实现多进程并行的问题
控制Bash循环任务的并发数(最多3个进程并行)
嘿,完全懂你的需求!你现在的写法确实是串行执行的——每次启动something lengthy &后立刻用wait $!等待这个进程跑完,才会进入下一次循环,所以永远只有一个任务在跑。要是直接把wait丢到循环外,所有任务会瞬间全部启动,文件多的话很容易把系统资源吃满,这肯定不是你想要的结果。
下面给你两种实用的解决方案,都能实现最多3个进程同时运行的目标:
方法1:用xargs快速实现(推荐,简洁直观)
xargs自带并发控制参数,一行就能搞定:
printf "%s\n" 1.txt 2.txt 3.txt 4.txt 5.txt | xargs -P 3 -I {} sh -c 'something lengthy "$@"' _ {}
-P 3:指定最多同时运行3个进程-I {}:把每个文件名替换到{}的位置- 最后的
_是给sh -c传的占位参数(避免把文件名当成脚本名)
方法2:在原循环基础上改造(灵活可控)
如果想保留原有的循环结构,可以通过计数器+进程ID数组来控制并发:
max_parallel=3 pids=() for file in 1.txt 2.txt 3.txt 4.txt 5.txt; do # 启动后台任务并记录进程ID something lengthy "$file" & pids+=($!) # 当并发数达到上限时,等待任意一个后台进程结束 if [ ${#pids[@]} -ge $max_parallel ]; then # wait -n 会等待第一个完成的进程(bash 4.3+支持) wait -n # 清理已完成的进程ID pids=($(ps -p "${pids[@]}" -o pid=)) fi done # 等待最后剩余的所有后台进程完成 wait "${pids[@]}"
如果你的bash版本低于4.3(不支持wait -n),可以用这个兼容性更好的版本:
max_parallel=3 pids=() for file in 1.txt 2.txt 3.txt 4.txt 5.txt; do something lengthy "$file" & pids+=($!) if [ ${#pids[@]} -ge $max_parallel ]; then # 等待第一个启动的进程完成,然后从数组中移除它的PID wait ${pids[0]} pids=("${pids[@]:1}") fi done wait "${pids[@]}"
这个逻辑是:每次启动任务后把PID存到数组里,当数组长度达到3时,等待第一个进程结束,再把它从数组里删掉,这样就能始终保持最多3个进程在运行。
内容的提问来源于stack exchange,提问作者d-b
相关产品推荐
相关产品推荐

