最小限の“タスクキュー”マルチコアCPUを活用するストックLinuxツール

StackOverflow https://stackoverflow.com/questions/832253

  •  06-07-2019
  •  | 
  •  

質問

bashと一般的なツールを使用して、Linux用の最小タスクキューシステムを構築する最良/最も簡単な方法は何ですか?

9'000行のファイルがあり、各行にはbashコマンドラインがあり、コマンドは完全に独立しています。

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log
...

私のボックスには複数のコアがあり、Xタスクを同時に実行したいです。これを行うための良い方法をウェブで検索しました。どうやら、多くの人がこの問題を抱えていますが、今のところ誰も良い解決策を持っていません。

ソリューションに次の機能があればいいと思います:

  • 複数のコマンドを解釈できます(例: command; command
  • 行のストリームリダイレクトを解釈できます(例: ls> /tmp/ls.txt
  • 一般的なLinuxツールのみを使用

ボーナスがあまりにもエキゾチックな要件なしで他のUnixクローンで動作する場合、ポイントします。

役に立ちましたか?

解決

コマンドリストをMakefileに変換できますか?その場合、「quote -j X」を実行するだけです。

他のヒント

GNU Parallel http://www.gnu.org/software/parallel/ はPPSSよりも一般的な並列化ツール。

実行ファイルに次が含まれる場合:

command 1 > Logs/1.log
command 2 > Logs/2.log
command 3 > Logs/3.log

できること:

cat runfile | parallel -j+0

CPUコアごとに1つのコマンドを実行します。

コマンドが上記のように単純な場合、runfileは必要ありませんが、実行できます:

seq 1 3 | parallel -j+0 'command {} > Logs/{}.log'

処理に使用できるコンピューターがさらにある場合は、GNU Parallelの--sshloginおよび--trcオプションを調べてください。

さて、ここに質問を投稿した後、私は有望に見える次のプロジェクトを見つけました。 a>。

編集:私が望んでいることとは異なり、PPSSは「ディレクトリA内のすべてのファイル」の処理に焦点を当てています。

まあ、とにかくこれは一種の楽しい質問です。

もちろん、 bash(1)を想定して、私がやることです。

  • これらのコマンドのうち、いくつが同時に有効に実行できるかを図で示します。コアの数だけになるわけではありません。 I / Oなどの多くのコマンドが中断されます。その番号Nを呼び出します。たとえば、 N = 15
  • SIGCHLDシグナルのトラップシグナルハンドラを設定します。これは、子プロセスが終了したときに発生します。 trap signalHandler SIGCHLD
  • コマンドのリストをパイプにまとめる
  • stdinを読み取り、コマンドを1つずつ実行して、カウンターをデクリメントするループを作成します。カウンターが0の場合、 wait sです。
  • SIGCHLDで実行されるシグナルハンドラ、インクリメントそのカウンタ。

したがって、最初の N コマンドを実行してから待機します。最初の子が終了すると、待機が戻り、別の行を読み取り、新しいコマンドを実行して、再び待機します。

現在、これは、多くのジョブが近くで終了することを処理するケースです。私はあなたがより簡単なバージョンで逃げることができる疑い

 N=15
 COUNT=N
 cat mycommands.sh | 
 while read cmd 
 do
   eval $cmd &
   if $((count-- == 0))
   then
       wait
   fi
 od

今、これは最初の15個のコマンドを起動し、コマンドが終了するたびに残りのコマンドを一度に実行します。

同様の分散コンピューティングの楽しみは、Mapreduce Bashスクリプトです:

http://blog.last.fm/2009/04 / 06 / mapreduce-bash-script

そしてppssを指摘してくれてありがとう!

xargs コマンドを使用すると、その-max-procs が必要な処理を実行できます。たとえば、Charlie Martinのソリューションはxargsを使用するようになります。

tr '\012' '\000' <mycommands.sh |xargs --null --max-procs=$X bash -c

詳細:

  • Xは最大プロセス数です。例:X = 15。 --max-procsはマジックを実行しています
  • 最初のtrは、xargs --nullオプションのnullバイトで行を終了し、引用符のリダイレクトなどが誤って拡張されないようにする
  • bash -cはコマンドを実行します

たとえば、このmycommands.shファイルでテストしました:

date
date "+%Y-%m-%d" >"The Date".txt
wc -c <'The Date'.txt >'The Count'.txt

これは特定のケースですが、ファイルのセットを処理して別の出力ファイルのセットを作成しようとしている場合、#cores個のプロセスを開始し、処理する前に出力ファイルが存在するかどうかを確認できます。以下の例は、.m4bファイルのディレクトリを.mp3ファイルに変換します。

コアの数だけこのコマンドを実行します:

ls * m4b | read read f;テスト-f $ {f%m4b} mp3 || rawaudio&quot; $ f&quot;のメンコーダー-oac mp3lame -ovc copy -o $ {f%m4b} mp3;完了&amp;

bashに書き込まれたタスクキューを見ることができます: https://github.com/pavelpat/yastq

タスクキュー+並列化+動的追加

FIFOを使用して、このスクリプトはそれ自体をフォークしてキューを処理します。この方法で、コマンドをその場でキューに追加できます(キューが既に開始されている場合)。

使用法:./queueコマンド[子の数] [キュー名]

例、1スレッド:

./queue "sleep 5; echo ONE"
./queue "echo TWO"

出力:

ONE
TWO

例、2スレッド:

./queue "sleep 5; echo ONE" 2
./queue "echo TWO"

出力:

TWO
ONE

例、2つのキューの場合:

./queue "sleep 5; echo ONE queue1" 1 queue1
./queue "sleep 3; echo ONE queue2" 1 queue2

出力:

ONE queue2
ONE queue1

スクリプト(&quot; queue&quot;およびchmod + x queueとして保存):

    #!/bin/bash

    #Print usage
    [[ $# -eq 0 ]] && echo Usage: <*> Command [# of children] [Queue name] && exit

    #Param 1 - Command to execute
    COMMAND="$1"

    #Param 2 - Number of childs in parallel
    MAXCHILD=1
    [[ $# -gt 1 ]] && MAXCHILD="$2"

    #Param 3 - File to be used as FIFO
    FIFO="/tmp/defaultqueue"
    [[ $# -gt 2 ]] && FIFO="$3"

    #Number of seconds to keep the runner active when unused
    TIMEOUT=5

    runner(){
      #Associate file descriptor 3 to the FIFO
      exec 3"$FIFO"

      while read -u 3 -t $TIMEOUT line; do
        #max child check
        while [ `jobs | grep Running | wc -l` -ge "$MAXCHILD" ]; do
          sleep 1
        done

        #exec in backgroud
        (eval "$line")&
      done
      rm $FIFO
    }

    writer(){
      #fork if the runner is not running
      lsof $FIFO >/dev/null || (<*> "QueueRunner" "$MAXCHILD" "$FIFO" &)

      #send the command to the runner
      echo "$COMMAND" > $FIFO
    }

    #Create the FIFO file
    [[ -e "$FIFO" ]] || mkfifo "$FIFO"

    #Start the runner if in the runner fork, else put the command in the queue
    [[ "$COMMAND" == "QueueRunner" ]] && runner || writer

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top