キューで実行するプログラムの要件に合わせて少し変更したスクリプトをGitHubで見つけました。
しかし、うまくいかず、理由がわかりません。実際、ジョブはキューファイルに反映されません。
GitHubページのリンクは次のとおりです。
https://gist.github.com/tubaterry/c6ef393a39cfbc82e13b8716c60f7824
これは私の修正版です。
#!/bin/sh
END="END"
true > queue
tail -n+0 -f queue | parallel -j 16 -E "$END"
while read i; do
echo "command [args] > ${i%.inp}.log 2> ${i%.inp}.err" > queue
done < "jobs.txt"
echo "$END" >> queue
echo "Waiting for jobs to complete"
while [ "$(pgrep 'perl /usr/local/bin/parallel' | grep -evc 'grep' | tr -d " ")" -gt "0" ]; do
sleep 1
done
touch killtail
mv killtail queue
rm queue
私が考えることができる唯一のことは、OpenBSDのステップの1つが期待どおりに機能しないことです。ただし、手順を再スケジュールし、すべてがエラーなしで実行されましたが、1つのジョブのみが送信されました。変更は、tail -n+0 -f queue | parallel -j 16 -E "$END"
最初のwhileループの後に移動し、これが何を意味するのかわからないためtrue > queue
に変更することです。touch queue
true > queue
どんな助けでも大変感謝します。
編集する:
実行したいコマンドへの入力ファイルパスで埋められたjobs.txtファイルがあります。 jobs.txtのファイルはコマンドの引数の1つになり、計算結果をログファイルに出力し、エラーはエラーファイルに出力します。
私の期待は、各ジョブがキューに追加され、最大16個のジョブがコアごとに1つずつ並列に実行されることです。これは、コマンドのパラメータの1つが一度に1つのコア使用率を計算するためです。これは、パラレル-Eパラメータで表される「END」に達するまで続きます。
作成したとおり、jobs.txtにはキューにエコーされる内容はありません。もう一度お試しください >>
原作で質問をたくさんしました。確かに知っていた部分を変更しましたが、本当に混乱してそのまま維持することに決めた機能もありました。
私がわからないことの1つはtail -n + 0です。
それが何をするのかわかりません。
編集2:
${PROGRAM} ${JOB}.inp ${NCPU} > ${JOB}.log 2> ${JOB}.err
$ {JOB}は、指定された時間に実行する必要がある操作の数に応じて、1から無限の計算の間の任意の場所への参照です。現在、jobs.txtには実行する必要がある374の個別のテストがあります。 ${PROGRAM} は、${JOB}.inp からパラメータを取得し、その計算を実行するソフトウェアです。 $ {NCPU}は、各ジョブに使用するコアの数です。現在、16コアプロセッサで各ジョブをシリアルで実行しようとしています。
目的は、コマンド全体を入力することなく、必要なだけ多くの計算をキューに追加することです。リスト生成を使用してfind calculations -name '*.inp' -print > jobs.txt
からスクリプト(SerialRun.shやParallelRun.shなど)を実行して結果を生成したいと思います。これらのタスクは、さまざまなユーザーがタスクを構成するために選択する方法に応じてさまざまなディレクトリに入れ子にすることができ、findを使用するこのアプローチにより、タスクを非常に迅速に送信し、結果を正しいパスに生成できます。各計算が完了した後、システムはテストを継続しながらデータを分析できます。
スクリプトが複雑すぎる可能性があります。私は作業キューシステムを探し、GNU Parallelプロジェクトになったnqsを見つけました。並列キュー操作の例はあまり見つかりませんでしたが、GitHubでこのスクリプトを見つけて試してみることにしました。私はそれが書かれている方法について多くの質問をしていますが、私はそれに疑問を抱くほど平行性をよく理解していません。
キューを設定する方がこれより簡単になると思います。
編集3:
おそらく正しい方法は次のとおりです。
while read i; do
command "$i" > "${i%.inp}".log 2> "${i%.inp}".err | parallel -j 16
done < "jobs.txt"
それはうまくいくでしょうか?
答え1
このような複雑なスクリプトは不要で、必要なものを自分で行うことがparallel
できます。必要な.inp
他のツールを使用してファイルリストから拡張子を削除し、sed
次のようにデフォルト名を入力しますparallel
。
sed 's/\.inp//' jobs.txt | parallel -j 16 "${PROGRAM} {}.inp > {}.log 2> {}.err"
この{}
記号は並列基本機能の一部であり、man parallel
以下に説明する。
{} 入力行。
置換文字列は、入力ソースから読み取られた行全体に置き換えられます。入力ソースは通常stdin(標準入力)ですが、またはを使用して指定することもでき
--arg-file
ます。:::
::::
したがって、並列に渡されたアイテムに置き換えられます。この場合、拡張子がsed
。
{.}
または、次のものを使用できます。
{.} 拡張子のない入力ラインです。
この代替文字列は、拡張子が削除された入力に置き換えられます。入力行に最後/末尾に.が含まれている場合、文字列の最後までの最後の.が削除され、{.}が残りの部分に置き換えられます。たとえば、 foo.jpg は foo になり、 subdir/foo.jpg は subdir/foo になり、 sub.dir/foo.jpg は sub.dir/foo になり、 sub.dir/bar は sub.dir/バーのままです。入力行にが含まれていない場合は変更されません。
置換文字列 {.} は --extensionreplace を使用して変更できます。
これを使用すると、ファイルは必要ありませんjobs.txt
。すべてのファイルが同じディレクトリにある場合は、次のことができます。
parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: *.inp
または、次のことを想定して、サブディレクトリに再帰的に降りるようにすることもできますbash
。
shopt -s globstar
parallel -j 16 "${PROGRAM} {.}.inp > {.}.log 2> {.}.err" ::: **/*.inp