【问题标题】:limit spawned parallel processes and exit all upon failure of any限制产生的并行进程并在任何失败时全部退出
【发布时间】:2016-03-11 20:19:48
【问题描述】:

我通过从脚本调用进程来并行运行一些测试。每个进程只打印到 stdout > 一个文件,如果成功则退出 0(否则 -1)。

如果一个进程以 -1 退出,我会在其(或相关的)输出文件(即调用它的参数)中打印一些内容,杀死所有其他进程,然后退出。

我使用trap "..." CHLD 编写了一个脚本,用于在子进程退出时运行一些代码,这在某些条件下有效,但我发现我的脚本不是很健壮。如果我发送键盘中断,有时子进程会继续运行,有时子进程的数量只会让机器不堪重负,而且它们似乎都没有进展。

我在我的四核笔记本电脑以及一个由 128 个 CPU 组成的集群上使用它,子进程自动分布在这些集群上。 如何在 bash 脚本中运行大量后台子进程,仅限于其中一些并发运行,如果其中一个返回错误代码,则执行某些操作 + 退出? 我也想键盘中断后清理的脚本。我应该使用 GNU 并行吗?怎么样?

到目前为止,这是我的脚本的 MWE,它不受阻碍地产生子流程,并用我认为每个部分的含义进行了注释。我从shell - get exit code of background process 得到了使用trap 的想法

$ cat parallel_tests.sh 
#!/bin/bash
# some help from https://stackoverflow.com/questions/1570262/shell-get-exit-code-of-background-process
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 先失败,其他两个进程在陷阱中处理。我在这里简化了测试过程的构造,所以我们不能假设我会在生成新的之前手动插入waits。此外,一些测试过程几乎是即时的。从本质上讲,我有一大堆测试过程,长短不一,只要资源分配好就开始。

我不确定是什么导致了我上面提到的问题,因为这个脚本使用了几个对我来说是新的功能。欢迎一般指点!

(我见过this question,它没有回答我的问题)

【问题讨论】:

  • 按下 CTRL-C 时终止在远程集群上运行的作业并非易事,因此即使您找到了可以在本地工作的解决方案,也不要认为它只能在远程工作。

标签: bash shell parallel-processing gnu-parallel


【解决方案1】:
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

【讨论】:

  • 如果我可以为自己澄清一下:我将 $ALL_ARGS 的每个项目写入文件 arguments(每行一个),然后将其 cat/pipe 到并行,其中 my_prg 是过程接受参数(例如我的示例中的sleep)。我还能从运行的作业中获取输出,并打印失败的作业的参数吗?
  • 是的,你可以得到。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-06
  • 1970-01-01
  • 2020-10-26
  • 2014-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多