【问题标题】:bash how to wait for completion of forked processes that run in backgroundbash如何等待在后台运行的分叉进程完成
【发布时间】:2018-01-12 22:29:00
【问题描述】:

我想知道我是否可以实现以下逻辑: 给定一组要完成的作业fold_num 和有限数量的工作进程,比如work_num,我希望并行运行work_num 进程,直到所有作业fold_num 完成。最后,对所有这些作业的结果还有一些其他的处理。我们可以假设fold_num 总是work_num 的几倍。

到目前为止,我还没有让以下 sn-p 工作,来自 How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0? 的提示

#!/bin/bash
worker_num=5                                                                                                                                                                                 
fold_num=10                                                                                                                                                                              

pids=""                                                                                                                                                                                   
result=0                                                                                                                                                                                  
for fold in $(seq 0 $(( $fold_num-1 ))); do                                                                                                                                               
    pids_idx=$(( $fold % ${worker_num} ))                                                                                                                                                    
    echo "pids_idx=${pids_idx}, pids[${pids_idx}]=${pids[${pids_idx}]}"                                                                                                                   
    wait ${pids[$pids_idx]} || let "result=1"                                                                                                                                             
    if [ "$result" == "1" ]; then                                                                                                                                                         
        echo "some job is abnormal, aborting"                                                                                                                                             
        exit                                                                                                                                                                              
    fi                                                                                                                                                                                    

    cmd="echo fold$fold"    # use echo as an example, real command can be time-consuming to run                                                                                                                                                              
    $cmd &                                                                                                                                                                                
    pids[${pids_idx}]="$!"                                                                                                                                                                

    echo "pids=${pids[*]}"                                                                                                                                                                
done                                                                                                                                                                                      


# when the for-loop completes, do something else...                                                                                                                                       

输出如下:

pids_idx=0, pids[0]=
pids=5846
pids_idx=1, pids[1]=
fold0
pids=5846 5847
fold1
pids_idx=2, pids[2]=
pids=5846 5847 5848
fold2
pids_idx=3, pids[3]=
pids=5846 5847 5848 5849
fold3
pids_idx=4, pids[4]=
pids=5846 5847 5848 5849 5850
pids_idx=0, pids[0]=5846
fold4
./test_wait.sh: line 12: wait: pid 5846 is not a child of this shell
some job is abnormal, aborting

问题: 1. 似乎pids 数组记录了正确的进程ID,但未能“等待”。任何想法如何解决这一问题? 2.我们需要在for循环之后使用wait吗?如果是这样,for循环之后该怎么办?

【问题讨论】:

  • 你能使用像 GNU Parallel 这样的工具吗? gnu.org/software/parallel
  • GNU Parallel 就是为此而设计的...parallel -j $work_num process ::: {1..$fold_num}
  • 我的真实命令有更复杂的逻辑,所以不确定并行是否可以实现这一点:假设我需要确保 fold0 和 fold5 由第一个工作进程(无论可能是什么)处理, fold1 和fold6 到第 2 次,... fold4 和 fold9 到第 5 次。我如何使用并行来做到这一点?

标签: bash wait


【解决方案1】:

好的,我想我得到了一个可行的解决方案,其中包含来自“parallel”的人们的提示。

export worker_names=("foo", "bar")                                                                                                                                                                                   
export worker_num=${#worker_names[@]}        

function some_computation {                                                                                                                                                                                          
    fold=$1                                                                                                                                                                                                          
    cmd="..."     #involves worker_names and fold                                                                                                                                                                    
    echo $cmd; $cmd                                                                                                                                                                                                  
}                                                                                                                                                                                                                    
export -f some_computation # important, to make this function visible to subprocesses                                                                                                                                

for fold in $(seq 0 $(( $fold_num-1 ))); do                                                                                                                                                                          
    sem -j $worker_num some_computation $fold                                                                                                                                                                        
done                                                                                                                                                                                                                 

sem --wait    # wait for all jobs to complete  

# do something below

这里有几件事:

  1. 我没有得到parallel 的工作,因为我需要在这些并行作业之后进行计算后处理。我尝试的并行版本未能等待作业完成。所以我使用了 GNU sem,它代表信号量。
  2. 在这种情况下,导出变量对于计算函数的访问至关重要。否则这些全局变量是不可见的。
  3. 出于同样的原因,也需要导出计算函数。注意-f 选项。

  4. sem --wait 完美地满足了等待并行作业的需求。

HTH。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-25
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-31
    相关资源
    最近更新 更多