stdinを並列プロセスに伝播

stdinを並列プロセスに伝播

標準入力でファイルのリストを処理するタスクがあります。プログラムの起動に時間がかかり、所要時間はファイルごとに大きく異なります。私はこれらのプロセスをたくさん作成し、使用していないプロセスにタスクを割り当てたいと思います。私が望むことをほとんど実行するいくつかのコマンドラインツールがあり、2つのオプションでほぼ機能しています。

find . -type f | split -n r/24 -u --filter="myjob"
find . -type f | parallel --pipe -u -l 1 myjob

問題はsplit純粋にループであるため、プロセスの1つが遅れてジョブ全体の完了を遅らせ、同時にparallelN行またはNバイトの入力ごとにプロセスを作成しようとしていることです。開始オーバーヘッドに時間がかかりすぎました。

プロセスを再利用し、ブロックされていない標準入力を使用してプロセスにラインを供給するようなものはありますか?

答え1

GNU Parallel の場合、 --block を使用してブロックサイズを設定できます。ただし、実行中のプロセスごとにメモリに1ブロックを保持するには十分なメモリが必要です。

これはまさにあなたが探しているものではないことを知っていますが、現在は許容可能な解決策かもしれません。

タスクに平均して同じ時間がかかる場合は、mbufferを使用できます。

find . -type f | split -n r/24 -u --filter="mbuffer -m 2G | myjob"

答え2

一般的なケースでは不可能に見えます。つまり、各プロセスにはバッファがあり、外部でバッファを観察して、次の項目をどこに配置するかを決定できます(スケジューリング)...もちろん何かを書くことができます(またはslurmなどのバッチシステムを使用できます)。

ただし、プロセスによっては入力を前処理することもできます。たとえば、ファイルをダウンロードしたり、データベースからアイテムを更新したり、そのうちの50%がスキップされた場合(したがって、入力によって処理に大きな違いがある)、設定するだけです。どの項目に長い時間がかかるか(ファイルが存在するか、データが変更されたかなど)検証する前処理装置があるため、反対側から来るすべての項目にはかなり同じ時間がかかります。ヒューリスティックが完璧ではなくても、おそらくかなりの進歩を遂げることができるでしょう。他のファイルをファイルにダンプし、同じ方法で処理できます。

ただし、ユースケースによって異なります。

答え3

いいえ、普遍的な解決策はありません。スケジューラは、各プログラムがいつ別の行を読む準備ができたかを知る必要がありますが、私が知っている限り、これを許可する標準はありません。あなたができることは、STDOUTにラインを追加し、パイプで生産者がそれを消費するのを待つだけです。実際、次のコンシューマーが準備されているかどうかを知るための良い方法はありません。

答え4

この試み:

mkfifoすべてのプロセスについて。

その後、tail -f | myjob各fifoにぶら下がります。

たとえば、ワーカー設定(myjobプロセス)

mkdir /tmp/jobs
for X in 1 2 3 4
do
   mkfifo pipe$X
   tail -f pipe$X | myjob &
   jobs -l| awk '/pipe'$X'/ {print $2, "'pipe$X'"}' >> pipe-job-mapping
done

アプリケーション(myjob)によっては、jobs -sを使用して停止したジョブを見つけることができます。それ以外の場合は、CPUごとにソートされたプロセスを一覧表示し、最も少ないリソースを消費するプロセスを選択します。たとえば、追加のジョブが必要な場合は、ファイルシステムにフラグを設定してジョブレポート自体を作成します。

入力待機中にジョブが停止したと仮定する場合は、次のようにします。

jobs -slたとえば、停止したジョブのpidを見つけてジョブを割り当てます。

grep "^$STOPPED_PID" pipe-to-job-mapping | while read PID PIPE
do
   cat workset > $PIPE
done

私はこれをテストしました

garfield:~$ cd /tmp
garfield:/tmp$ mkfifo f1
garfield:/tmp$ mkfifo f2
garfield:/tmp$ tail -f f1 | sed 's/^/1 /' &
[1] 21056
garfield:/tmp$ tail -f f2 | sed 's/^/2 /' &
[2] 21058
garfield:/tmp$ echo hello > f1
1 hello
garfield:/tmp$ echo what > f2
2 what
garfield:/tmp$ echo yes > f1
1 yes

私はこれが単に操作されたことを認めなければなりません。だからymmv。

関連情報