2016-11-01 18 views
0

大量のシミュレーションデータを生成するためにジョブを継続的に実行するためのbashスクリプトを書いています。bashプログラミング、バックグラウンドプロセス、PIDとジョブが終了するのを待つ

本質的にスクリプトが実行されると、32個以下の同時バックグラウンドジョブを実行できるという制約の下で、バックグラウンドプロセスを継続的に起動してデータを生成する必要があります。これは、プロセスが使用可能なすべてのRAMを盛り上げて、サーバーを停止させないようにするために必要です。

私の考えは、バックグラウンドでbash関数を起動し、それらのジョブのPIDを保存することでした。その後、32個のジョブが起動した後、ジョブのすべてのPIDが実行を終了するまで、waitコマンドをwaitに使用します。

私はwaitが、waitコマンドが実行されたときにプロセスのpidが存在する限り(ここではシミュレーションを実行するのに6時間かかります)、waitコマンドがプロセスは終了する。

これはプロセスをポーリングするだけでなく、特定のPIDが存在するかどうかをチェックするよりも、PIDがリサイクルされ、同じPIDで終了した後に別のプロセスが開始された可能性があります。

しかし、waitメソッドを使用すると、プロセスが実行された順序で終了しなければ、もはや存在しないPIDのためにwaitが呼び出されるという欠点があります(不運な場合はランダムチャンスです)。新しいプロセスが以前に記録したものと同じPIDを再使用しない限り、またあるジョブが他のジョブよりもかなり長い時間がかかった場合(偶然にも)、余裕がある間に1つのジョブが終了するのを待つその最後のPIDを終了するために、我々は待っているので、実行することはできません別の31のジョブ、システム...

これはおそらく

...ので、私はいくつかのコードを追加してみましょう可視化するビット困難になってきています10

私はうまくいけば、コード内のコメントや上記のコードとコメントの組み合わせは、私がしようとしていますどのようなことを明確にする必要があり、この「アルゴリズム」

c=0 # count total number of jobs launched (will not really use this here) 
PIDS=() # keep any array of PIDs 

# maximum number of simultaneous jobs and counter 
BATCH_SIZE=32 
BATCH_COUNT=0 

# just start looping 
while true 

    # edit: forgot to add this initially 
    # just check to see if a job has been run using file existance 
    if [ ! -e "$FILE_NAME_1" ] 
    then 

     # obvious 
     if [ "$BATCH_COUNT" -lt "$BATCH_SIZE" ] 
     then 

      ((BATCH_COUNT += 1)) 

      # this is used elsewhere to keep track of whether a job has been executed (the file existence is a flag)  
      touch "$FILE_NAME_1" 
      # call background job, parallel_job_run is a bash function 
      parallel_job_run $has_some_arguments_but_not_relevent 
      # get PID 
      PID=$! 
      echo "[ JOB ] : Launched job as PID=$PID" 
      PIDS+=($PID) 

      # count total number of jobs 
      ((c=c+1)) 
     fi 

    else 
     # increment file name to use as that file already exists   
     # the "files" are for input/output 
     # the details are not particularly important 
    fi 

    true # prevent exit 

# the following is a problem 
do  
    if ((BATCH_COUNT < BATCH_SIZE)) 
    then 
     continue 
    else 
     # collect launched jobs 
     # this does not collect jobs in the order that they finish 
     # it will first wait for the first PID in the array to exit 
     # however this job may be the last to finish, in which case 
     # wait will be called with other array values with PID's which 
     # have already exited, and hence it is undefined behaviour 
     # as to whether we wait for a PID which doesn't exist (no problem) 
     # or a new process may have started which re-uses our PID 
     # and therefore we are waiting for someone else's process 
     # to finish which is nothing to do with our own jobs! 
     # we could be waiting for the PID of someone else's tty login 
     # for example! 
     for pid in "${PIDS[@]}" 
     do 
      wait $pid || echo "failed job PID=$pid" 
      ((BATCH_COUNT -= 1)) 
     done 
    fi 

done 

の基盤としてwhileループを使用しています。

私の他の考え方は、最後のforループを、それぞれのPIDが存在するかどうかを絶えず調べる別のループに置き換えることでした。 (Polling。)これはCPUのホギングを防ぐためにsleep 1と組み合わせることができます。しかし、この問題は以前と同じように、私たちのプロセスはPIDを解放して終了し、PIDを取得する別のプロセスが実行されることがあります。この方法の利点は、前のプロセスが終了したときに新しいプロセスが開始される前に約1秒以上待つことがないことです。

私はここにいる問題をどのように進めるべきか、誰にでも助言できますか?

私は今日この問題を絶えず更新しています。たとえば、見つかったら新しい情報を追加し、それを明確にするために書式/書式を設定します。

答えて

1

-nオプションをwaitと使用すると、そのPIDに関係なく次のプロセスが完了するのを待ちます。だから、それは一つの解決策かもしれません。

また、Linuxは、あなたが暗示しているように、すぐにPIDをリサイクルしません。次の使用可能なPIDを新しいプロセスに順番に割り当て、使用可能な最大PIDを使い果たした後でのみ、最初から開始します。

関連する問題