シェル並列処理:付加価値

シェル並列処理:付加価値

簡単な例では、シェルスクリプトでの並列処理を理解し、出力に決定的に(ランダムな順序ではなく)順番に値を追加したいと思います。コードスニペットは次のとおりです。

x=""
appendnum() {
    num=$1; x=`echo $x$num`
}
for no in {0..10}
do
    appendnum $no &
done
wait $(jobs -rp)
echo $x

期待される出力は012345678910でしたが、結果はnullでした。完了するまでPIDを繰り返しようとしましたが、成功しませんでした。メインスレッドは、各並列プロセスが完了するのを待つことを望みます。追加の数値は一例です。

私の問題の説明は次のとおりです。 3つのタスクがあることを考えると、次のような応答リストが欲しいです[responseof(task1),responseof(task2),responseof(task3)]。ジョブ数は最大50個まで可能です。ジョブ数に関係なく、応答時間は同じでなければなりません。最も効率的で正しい方法は何ですか?

答え1

私が正しく理解した場合は、次のようにします。

  • ジョブを並列に実行します。理想的には、単一のジョブを実行する時間内にこれらのすべてのジョブが完了するようにする必要があります。 (とても現実的ではありませんが、頑張って頑張ってみます)
  • 一部の後続のジョブが前のジョブの前に完了しても、出力順序を維持します。

これを念頭に置いて、次のことを試すことができます。

parallel -k -j10 'sleep {}; echo -n {}' ::: {10..1}

実行される最初の操作は最も時間がかかりますが、オプションを追加したため、-kユーティリティparallelは順序を維持して最終的に出力します。

10987654321

この-kオプションがない場合、出力は反転され、コマンドが完了すると表示されます。

12345678910

詳細が必要な場合は、チュートリアルを確認してください。https://www.gnu.org/software/parallel/parallel_tutorial.html

答え2

あなたが逃しているもの:

  • シェル変数はシェルメモリ、つまりシェルプロセスのメモリに格納されます。
  • ほとんどのコマンドは、子プロセスで実行されるシェルで実行されます。唯一の例外は「組み込みコマンド」です。
  • 非同期コマンドは、プログラムを実行しなくても常に子プロセスで実行されます。プログラムを実行しない非同期コマンドは、シェルのみを実行する子プロセスです。これを「サブシェル」といいます。
  • 通常、プロセスは他のプロセスのメモリを変更できません。特に、サブシェルはメインシェルプロセスの変数を変更できません。だからあなたが言うときappendnum $no &appendnum機能 できないxデフォルトのシェルプロセスで変数を変更します。

望むものと同様の動作を得ることができる。

x=TR007.out
> "$x"
appendnum() {
    echo "$1" >> "$x"
}
for no in {0..10}
do
    appendnum $no &
done
wait

ファイルに0から10までの数字を書き込みますTR007.out

  • 非同期プロセスのスケジューリング(順序付け)は非決定的です。したがって、上記のサンプルスクリプトでは、0から10までの数字をファイルに書き込んでも順序が合わないことがあります。
  • ご存知のwaitように、パラメータなしでそれ自体がすべての子プロセスを待ちます。
  • 「ジョブ数に関係なく、応答時間は同じでなければなりません。」これは非常に大胆な期待/要件です。これが合理的かどうかは状況によって異なります。タスクが単一スレッドのコンピューティング集約的なタスクであり、3つ以上の(論理的な)CPUがある場合、3つのタスクを並列に実行することは、1つのタスク自体よりも少し時間がかかると予想するのが妥当です。 。しかし、論理CPUが4つであれば完全に大丈夫です。無謀1つのジョブと同じ時間内に50のジョブが実行されると予想されます。
  • 子(非同期)プロセスは予想される順序で実行されると述べました。同時に(つまり、並列に)実行されるため、実行が重複する可能性があります。したがって、上記のスクリプトを次のように変更すると、
    付録(){
        エコ"$1"a>>"$x"
        エコ "$1"b>>"$x"
    }
    {1..3}の「いいえ」について
    する
        付録$いいえ&
    完璧
    その後、ファイルから/////を取得したり、1a/////を取得したり、/////を取得したり、さらに悪いことがあります。非同期プロセスを同じファイルに書き込むことはお勧めできません。1b2a2b3a3b2a2b1a1b3a3b2a1a2b3a3b1b

おそらく、次のことを行う必要があります。

{1..3}の「いいえ」について
する
    タスク "$no" > ファイル "$no" &
完璧
待つ
catファイル1ファイル2ファイル3>結果の組み合わせ
その他の注意事項:

  • $(command)同じことをしながら。テーブルに貼り付ける必要があります。`command`$(command)
  • 言うかどうかは意味がありません。言う。x=`echo $x$num`x=$(echo $x$num)x="$x$num"
  • そうしない妥当な理由がなく、自分が何をしているのかを知らない限り、常にシェル変数を引用する必要があります。だからしないでくださいappendnum $noappendnum "$no"

答え3

[応答(タスク1)、応答(タスク2)、応答(タスク3)]

parset以下のために作られています:

parset result responseof ::: task1 task2 task3
echo "${result[1]}"

たとえば、

parset res seq ::: 3 2 1
echo "${res[1]}"

parsetGNU Parallelの一部です。

関連情報