限制产生的并行进程并在任何失败时退出所有
limit spawned parallel processes and exit all upon failure of any
我正在 运行通过从脚本调用进程来并行进行一些测试。每个进程只打印到 stdout > 一个文件,如果成功则退出 0(否则 -1)。
如果一个进程以 -1 退出,我会在它的(或相关的)输出文件中打印一些东西(即调用它的参数),杀死所有其他进程,然后退出。
我已经使用 trap "..." CHLD
编写了一个脚本,以便在子进程退出时使用 运行 一些代码,这在某些条件下有效,但我发现我的脚本不是很健壮。如果我发送键盘中断,有时子进程会继续运行,有时子进程的数量只会压倒机器,并且 none 似乎在前进。
我在我的四核笔记本电脑和一个由 128 个 CPU 组成的集群上使用它,子进程自动分布在这些 CPU 上。 我如何在 bash 脚本中 运行 大量后台子进程,并发地限制其中的某些数量 运行ning,并且如果其中之一执行某些操作 + 退出他们 returns 代码错误? 我还希望脚本在键盘中断后进行清理。我应该使用 GNU-parallel 吗?怎么样?
这是到目前为止我的脚本的 MWE,它不受阻碍地生成子进程,并注释了我认为每个部分的含义。我想到了使用 shell - get exit code of background process
中的 trap
$ cat parallel_tests.sh
#!/bin/bash
# some help from
handle_chld() {
#echo pids are ${pids[@]}
local tmp=() ###temporary storage for pids that haven't finished
#for each pid that hadn't finished since the last trap
for((i=0;i<${#pids[@]};++i)); do
#if this pid is still running
if [[ $(ps -p ${pids[i]} -o pid=) ]]
then
tmp+=(${pids[i]}) ### add pid to list of pids that are running
else
wait ${pids[i]} ### put the exit code of this pid into $?
if [ "$?" != "0" ] ### if the exit code $? is non-zero
then
#kill all remaning processes
for((j=0;j<${#pids[@]};++j))
do
if [[ $(ps -p ${pids[j]} -o pid=) ]]
then
echo killing child processes of ${pids[j]}
pkill -P ${pids[j]}
fi
done
cat _tmp${pids[i]}
#print things to the terminal here
echo "FAILED process ${pids[i]} args: `cat _tmpargs${pids[i]}`"
exit 1
else
echo "FINISHED process ${pids[i]} args: `cat _tmpargs${pids[i]}`"
fi
fi
done
#update list of running pids
pids=(${tmp[@]})
}
# set this to monitor SIGCHLD
set -o monitor
# call handle_chld() when SIGCHLD signal is triggered
trap "handle_chld" CHLD
ALL_ARGS="2 32 87" ### ad nauseam
for A in $ALL_ARGS; do
(sleep $A; false) > _tmp$! &
pids+=($!)
echo $A > _tmpargs${pids[${#pids[@]}-1]}
echo "STARTED process ${pids[${#pids[@]}-1]} args: `cat _tmpargs${pids[${#pids[@]}-1]}`"
done
echo "Every process started. Now waiting on PIDS:"
echo ${pids[@]}
wait ${pids[@]} ###wait until every process is finished (or exit in the trap)
这个版本在 2+epsilon 秒后的输出是:
$ ./parallel_tests.sh
STARTED process 66369 args: 2
STARTED process 66374 args: 32
STARTED process 66381 args: 87
Every process started. Now waiting on PIDS:
66369 66374 66381
killing child processes of 66374
./parallel_tests.sh: line 43: 66376 Terminated: 15 sleep $A
killing child processes of 66381
./parallel_tests.sh: line 43: 66383 Terminated: 15 sleep $A
FAILED process 66369 args: 2
本质上是pid 66369先失败,其他两个进程在trap中处理。我在这里简化了测试过程的构造,所以我们不能假设我会在产生新的之前手动插入 wait
s。此外,一些测试过程几乎是即时的。本质上,我有一大堆测试过程,长的和短的,只要可以分配资源就开始。
我不确定是什么导致了我上面提到的问题,因为这个脚本使用了几个对我来说是新的功能。欢迎大家指点!
(我看过this question但没有回答我的问题)
cat arguments | parallel --halt now,fail=1 my_prg
或者:
parallel --halt now,fail=1 my_prg ::: $ALL_ARGS
GNU Parallel 的设计目的是它也会终止远程作业。它在远程服务器上使用进程组和繁重的 perl 脚本来做到这一点:https://www.gnu.org/software/parallel/parallel_design.html#The-remote-system-wrapper
我正在 运行通过从脚本调用进程来并行进行一些测试。每个进程只打印到 stdout > 一个文件,如果成功则退出 0(否则 -1)。
如果一个进程以 -1 退出,我会在它的(或相关的)输出文件中打印一些东西(即调用它的参数),杀死所有其他进程,然后退出。
我已经使用 trap "..." CHLD
编写了一个脚本,以便在子进程退出时使用 运行 一些代码,这在某些条件下有效,但我发现我的脚本不是很健壮。如果我发送键盘中断,有时子进程会继续运行,有时子进程的数量只会压倒机器,并且 none 似乎在前进。
我在我的四核笔记本电脑和一个由 128 个 CPU 组成的集群上使用它,子进程自动分布在这些 CPU 上。 我如何在 bash 脚本中 运行 大量后台子进程,并发地限制其中的某些数量 运行ning,并且如果其中之一执行某些操作 + 退出他们 returns 代码错误? 我还希望脚本在键盘中断后进行清理。我应该使用 GNU-parallel 吗?怎么样?
这是到目前为止我的脚本的 MWE,它不受阻碍地生成子进程,并注释了我认为每个部分的含义。我想到了使用 shell - get exit code of background process
中的trap
$ cat parallel_tests.sh
#!/bin/bash
# some help from
handle_chld() {
#echo pids are ${pids[@]}
local tmp=() ###temporary storage for pids that haven't finished
#for each pid that hadn't finished since the last trap
for((i=0;i<${#pids[@]};++i)); do
#if this pid is still running
if [[ $(ps -p ${pids[i]} -o pid=) ]]
then
tmp+=(${pids[i]}) ### add pid to list of pids that are running
else
wait ${pids[i]} ### put the exit code of this pid into $?
if [ "$?" != "0" ] ### if the exit code $? is non-zero
then
#kill all remaning processes
for((j=0;j<${#pids[@]};++j))
do
if [[ $(ps -p ${pids[j]} -o pid=) ]]
then
echo killing child processes of ${pids[j]}
pkill -P ${pids[j]}
fi
done
cat _tmp${pids[i]}
#print things to the terminal here
echo "FAILED process ${pids[i]} args: `cat _tmpargs${pids[i]}`"
exit 1
else
echo "FINISHED process ${pids[i]} args: `cat _tmpargs${pids[i]}`"
fi
fi
done
#update list of running pids
pids=(${tmp[@]})
}
# set this to monitor SIGCHLD
set -o monitor
# call handle_chld() when SIGCHLD signal is triggered
trap "handle_chld" CHLD
ALL_ARGS="2 32 87" ### ad nauseam
for A in $ALL_ARGS; do
(sleep $A; false) > _tmp$! &
pids+=($!)
echo $A > _tmpargs${pids[${#pids[@]}-1]}
echo "STARTED process ${pids[${#pids[@]}-1]} args: `cat _tmpargs${pids[${#pids[@]}-1]}`"
done
echo "Every process started. Now waiting on PIDS:"
echo ${pids[@]}
wait ${pids[@]} ###wait until every process is finished (or exit in the trap)
这个版本在 2+epsilon 秒后的输出是:
$ ./parallel_tests.sh
STARTED process 66369 args: 2
STARTED process 66374 args: 32
STARTED process 66381 args: 87
Every process started. Now waiting on PIDS:
66369 66374 66381
killing child processes of 66374
./parallel_tests.sh: line 43: 66376 Terminated: 15 sleep $A
killing child processes of 66381
./parallel_tests.sh: line 43: 66383 Terminated: 15 sleep $A
FAILED process 66369 args: 2
本质上是pid 66369先失败,其他两个进程在trap中处理。我在这里简化了测试过程的构造,所以我们不能假设我会在产生新的之前手动插入 wait
s。此外,一些测试过程几乎是即时的。本质上,我有一大堆测试过程,长的和短的,只要可以分配资源就开始。
我不确定是什么导致了我上面提到的问题,因为这个脚本使用了几个对我来说是新的功能。欢迎大家指点!
(我看过this question但没有回答我的问题)
cat arguments | parallel --halt now,fail=1 my_prg
或者:
parallel --halt now,fail=1 my_prg ::: $ALL_ARGS
GNU Parallel 的设计目的是它也会终止远程作业。它在远程服务器上使用进程组和繁重的 perl 脚本来做到这一点:https://www.gnu.org/software/parallel/parallel_design.html#The-remote-system-wrapper