![Bash:等待固定数量的进程](https://linux22.com/image/126393/Bash%EF%BC%9A%E7%AD%89%E5%BE%85%E5%9B%BA%E5%AE%9A%E6%95%B0%E9%87%8F%E7%9A%84%E8%BF%9B%E7%A8%8B.png)
我编写了一个 bash 脚本,用于执行 Java jarn次数。
在实践中,我定义了 e富()函数,包含调用罐,然后我运行这个脚本:
for RUN in $(seq 1 $RUNS)
do
foo &
done
现在,我不想执行运行并行的时间罐。是否有等待限制并行执行的数量(例如wait
每 10 个进程)?
答案1
bash
4.4 版引入了一个有用的新习惯用法,称为参数变换在这种情况下这可以帮助你。在下面的代码片段中,请注意${num_jobs@P}
.这@P
是一种类型参数变换这会导致变量像提示字符串一样展开bash
。参见man bash
其他参数变换选项。
#!/bin/bash
num_procs=$1
num_iters=$2
num_jobs="\j" # The prompt escape for number of jobs currently running
for ((i=0; i<num_iters; i++)); do
while (( ${num_jobs@P} >= num_procs )); do
wait -n
done
foo &
done
归功于切普纳https://stackoverflow.com/a/38775799/6631810。
根据 Kusalananda 的评论,如果需要,为了使这组进程独立于任何其他会影响计数的后台作业,您可以用它们自己的 shell 来包装它们。为此,需要进行一些更改。
#!/bin/bash
# start a wrapper shell for the group of jobs
cat<<EOS | bash &
num_procs="$1"
num_iters="$2"
for ((i=0; i<num_iters; i++)); do
# escape what's not supposed to be expanded
# at the time of here-doc redirection
while (( \${num_jobs@P} >= num_procs )); do
wait -n
done
foo &
done
EOS
# now you can do other things
答案2
for RUN in $(seq 1 $RUNS); do
foo &
if (( (RUN % 10) == 0 )); then
wait
fi
done
或者,使用替代循环构造(恕我直言,看起来更好):
for (( r = 1; r <= RUNS; ++i )); do
foo &
if (( (r % 10) == 0 )); then
wait
fi
done
如果不是 10 的倍数,您可能还需要wait
在循环后添加一个单独的值。$RUNS
除了RUNS
运行总数之外,我们还可以想象有n
10 个作业的批次:
for (( i = 0; i < n; ++i )); do
printf 'starting batch %d...\n' "$i"
for (( j = 0; j < 10; ++j )); do
foo &
done
echo 'waiting...'
wait
done
xargs
使用并且没有显式的替代解决方案wait
:
seq 1 "$RUNS" | xargs -n 1 -P 10 foo
然而,这会给进程一个可能不需要的foo
命令行参数(由 生成的整数之一)。seq
这消除了这个问题:
seq 1 "$RUNS" | xargs -n 1 -P 10 sh -c 'foo'
答案3
GNU Parallel 正是为此而设计的:
seq 1 $RUNS | parallel -j 10 -N0 foo
默认情况下,每个 CPU 核心运行一项作业:
seq 1 $RUNS | parallel -N0 foo
GNU Parallel 是一个通用并行器,可以轻松地在同一台计算机或多台您可以通过 ssh 访问的计算机上并行运行作业。
如果您想要在 4 个 CPU 上运行 32 个不同的作业,则并行化的直接方法是在每个 CPU 上运行 8 个作业:
相反,GNU Parallel 在完成后会生成一个新进程 - 保持 CPU 处于活动状态,从而节省时间:
安装
出于安全原因,您应该使用软件包管理器安装 GNU Parallel,但如果 GNU Parallel 未针对您的发行版打包,您可以进行个人安装,这不需要 root 访问权限。这样做可以在 10 秒内完成:
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
对于其他安装选项,请参阅http://git.savannah.gnu.org/cgit/parallel.git/tree/README
了解更多
查看更多示例:http://www.gnu.org/software/parallel/man.html
观看介绍视频:https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
浏览本教程:http://www.gnu.org/software/parallel/parallel_tutorial.html
注册电子邮件列表以获得支持:https://lists.gnu.org/mailman/listinfo/parallel