43

実行するタスクが10を超えていますが、システムでは、最大4つのタスクを同時に実行できるように制限されています。

私のタスクは次のように開始できます:myprog taskname

これらのタスクを実行するためのbashシェルスクリプトを作成するにはどうすればよいですか。最も重要なことは、1つのタスクが終了すると、スクリプトは別のタスクをすぐに開始できるため、実行中のタスクのカウントが常に4のままになることです。

4

12 に答える 12

62

使用xargs:

xargs -P <maximum-number-of-process-at-a-time> -n <arguments-per-process> <command>

詳細はこちら

于 2013-10-27T12:44:06.740 に答える
18

GNU Parallel を使用すると、次のことができます。

cat tasks | parallel -j4 myprog

コアが 4 つある場合は、次のようにすることもできます。

cat tasks | parallel myprog

http://git.savannah.gnu.org/cgit/parallel.git/tree/READMEから:

フルインストール

GNU Parallel のフル インストールは次のように簡単です。

./configure && make && make install

個人的なインストール

root でない場合は、~/bin をパスに追加して、~/bin および ~/share にインストールできます。

./configure --prefix=$HOME && make && make install

または、システムに「make」がない場合は、src/parallel src/sem src/niceload src/sql をパスのディレクトリにコピーするだけです。

最小限のインストール

並列が必要で、「make」がインストールされていない場合 (システムが古いか、Microsoft Windows である可能性があります):

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
mv parallel sem dir-in-your-$PATH/bin/

インストールをテストする

この後、次のことができるはずです。

parallel -j0 ping -nc 3 ::: foss.org.my gnu.org freenetproject.org

これにより、3 つの ping パケットが 3 つの異なるホストに並行して送信され、完了すると出力が出力されます。

簡単な紹介については、紹介ビデオをご覧ください: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

于 2013-03-15T16:42:50.310 に答える
5

4 つのスクリプトを作成し、それぞれが一定数のタスクを連続して実行することをお勧めします。次に、4 つのスクリプトを並行して開始する別のスクリプトを作成します。たとえば、script1.sh、script2.sh、script3.sh、および script4.sh というスクリプトがある場合、headscript.sh というスクリプトを作成できます。

#!/bin/sh
./script1.sh & 
./script2.sh & 
./script3.sh & 
./script4.sh &
于 2011-06-22T14:32:17.170 に答える
1

おそらく、シグナルで何か賢いことができるでしょう。

これは概念を説明するためのものであり、完全にテストされていないことに注意してください。

#!/usr/local/bin/bash

this_pid="$$"
jobs_running=0
sleep_pid=

# Catch alarm signals to adjust the number of running jobs
trap 'decrement_jobs' SIGALRM

# When a job finishes, decrement the total and kill the sleep process
decrement_jobs()
{
  jobs_running=$(($jobs_running - 1))
  if [ -n "${sleep_pid}" ]
  then
    kill -s SIGKILL "${sleep_pid}"
    sleep_pid=
  fi
}

# Check to see if the max jobs are running, if so sleep until woken
launch_task()
{
  if [ ${jobs_running} -gt 3 ]
  then
    (
      while true
      do
        sleep 999
      done
    ) &
    sleep_pid=$!
    wait ${sleep_pid}
  fi

  # Launch the requested task, signalling the parent upon completion
  (
    "$@"
    kill -s SIGALRM "${this_pid}"
  ) &
  jobs_running=$((${jobs_running} + 1))
}

# Launch all of the tasks, this can be in a loop, etc.
launch_task task1
launch_task tast2
...
launch_task task99
于 2011-06-22T19:40:08.243 に答える
1

このテスト済みのスクリプトは、一度に 5 つのジョブを実行し、新しいジョブを再起動します (SIGCHLD を取得するとスリープ 10.9 が強制終了されるため)。これのより単純なバージョンでは、直接ポーリングを使用できます (スリープ 10.9 を1スリープしてトラップを取り除きます)。

#!/usr/bin/bash

set -o monitor
trap "pkill -P $$ -f 'sleep 10\.9' >&/dev/null" SIGCHLD

totaljobs=15
numjobs=5
worktime=10
curjobs=0
declare -A pidlist

dojob()
{
  slot=$1
  time=$(echo "$RANDOM * 10 / 32768" | bc -l)
  echo Starting job $slot with args $time
  sleep $time &
  pidlist[$slot]=`jobs -p %%`
  curjobs=$(($curjobs + 1))
  totaljobs=$(($totaljobs - 1))
}

# start
while [ $curjobs -lt $numjobs -a $totaljobs -gt 0 ]
 do
  dojob $curjobs
 done

# Poll for jobs to die, restarting while we have them
while [ $totaljobs -gt 0 ]
 do
  for ((i=0;$i < $curjobs;i++))
   do
    if ! kill -0 ${pidlist[$i]} >&/dev/null
     then
      dojob $i
      break
     fi
   done
   sleep 10.9 >&/dev/null
 done
wait
于 2011-06-22T20:09:43.550 に答える
0

4つのシェルスクリプトに関する他の回答は、すべてのタスクにほぼ同じ時間がかかると想定し、手動でセットアップする必要があるため、完全には満足できません。しかし、ここで私はそれを改善する方法を示します。

メイン スクリプトは、特定の命名規則に従って、実行可能ファイルへのシンボリック リンクを作成します。例えば、

ln -s executable1 ./01-task.01

最初のプレフィックスはソート用で、サフィックスはバッチを識別します (01-04)。ここで、バッチ番号を入力として取り、次のようなことを行う 4 つのシェル スクリプトを生成します。

for t in $(ls ./*-task.$batch | sort ; do
   t
   rm t
done
于 2011-06-22T15:33:07.483 に答える
0

bash でのジョブ プールの実装を見てください: https://github.com/spektom/shell-utils/blob/master/jp.sh

たとえば、多くの URL からダウンロードするときに cURL の最大 3 つのプロセスを実行するには、次のように cURL コマンドをラップできます。

./jp.sh "My Download Pool" 3 curl http://site1/...
./jp.sh "My Download Pool" 3 curl http://site2/...
./jp.sh "My Download Pool" 3 curl http://site3/...
...
于 2013-12-17T15:02:50.987 に答える
0

このWrite a process pool in Bash で紹介された方法に基づいて変更を加えました。

#!/bin/bash

#set -e   # this doesn't work here for some reason
POOL_SIZE=4   # number of workers running in parallel

#######################################################################
#                            populate jobs                            #
#######################################################################

declare -a jobs

for (( i = 1988; i < 2019; i++ )); do
    jobs+=($i)
done

echo '################################################'
echo '    Launching jobs'
echo '################################################'

parallel() {
    local proc procs jobs cur
    jobs=("$@")         # input jobs array
    declare -a procs=() # processes array
    cur=0               # current job idx

    morework=true
    while $morework; do
        # if process array size < pool size, try forking a new proc
        if [[ "${#procs[@]}" -lt "$POOL_SIZE" ]]; then
            if [[ $cur -lt "${#jobs[@]}" ]]; then
                proc=${jobs[$cur]}
                echo "JOB ID = $cur; JOB = $proc."

                ###############
                # do job here #
                ###############

                sleep 3 &

                # add to current running processes
                procs+=("$!")
                # move to the next job
                ((cur++))
            else
                morework=false
                continue
            fi
        fi

        for n in "${!procs[@]}"; do
            kill -0 "${procs[n]}" 2>/dev/null && continue
            # if process is not running anymore, remove from array
            unset procs[n]
        done
    done
    wait
}

parallel "${jobs[@]}"
于 2019-07-22T14:02:54.693 に答える