web-dev-qa-db-ja.com

GNU Parallelは、プログラムが終了するまでジョブを実行しません

実行すると(rss-notifierのコードが最後に含まれています)、

rss-notifier.zsh https://www.wuxiaworld.com/feed/chapters ".*"|parallel --null -k --lb echo {}

わかった、

Title: Sovereign of the Three Realms - ????Chapter 1339: Tears Of Joy
Link: https://www.wuxiaworld.com/novel/sovereign-of-the-three-realms/sotr-chapter-1339

Title: Renegade Immortal - Chapter 1259 - Rebuking the Everlasting Sect, Flowing Time
Link: https://www.wuxiaworld.com/novel/renegade-immortal/rge-chapter-1259

Title: Condemning the Heavens - Chapter 242: Three-eyed Troublemaker
Link: https://www.wuxiaworld.com/novel/condeming-the-heavens/cth-chapter-242

Title: Condemning the Heavens - Chapter 241: Join Us
Link: https://www.wuxiaworld.com/novel/condeming-the-heavens/cth-chapter-241

しかし、私が走ると、

rss-notifier.zsh https://www.wuxiaworld.com/feed/chapters ".*"|parallel --null -k --lb -N 2 echo {1} {2}

Parallelはプログラムが最初に終了するのを待つため、何も得られません。

どうすればこの問題を解決できますか? stdinから読み取る2つのnullで区切られた文字列ごとにcommand {1} ... {2}を並列で実行したいだけです。

これがrss-notifierです:

#!/usr/bin/env zsh
rsstail -l -u "$1" -n 9 | while read -r line1
do
    read -r line2
    if ggrep -P --silent "$2" <<< "$line1" ; then
        printf '%b' "$line1"'\0'"$line2"'\0'
        echo
    fi
done

または、より単純な再現者の場合:

(printf '%s\0' {1..4}; sleep 2) | parallel --null -k --lb -N 2 echo {1} {2}

更新:ユースケースを実現できる代替ユーティリティにも満足します。 xargsでそれを行う方法は次のとおりですが、あまり優雅ではありません。

xargsを介して複数のパラメーターを渡す

4
HappyFace

あなたは2つの問題に見舞われています。

この

_(seq 200; sleep 20) | parallel -j10  -k echo
_

プリント:

_1
2
_

その後、_sleep 20_が完了するまでストールします。

部分的な修正は、start_more_jobs()whileループの外に移動することのようです。

_--- a/src/parallel
+++ b/src/parallel
@@ -4062,9 +4062,8 @@ sub reaper {
        # $stiff = pid of dead process
        if(wantarray) {
            Push(@pids_reaped,$stiff);
-       } else {
-           $children_reaped++;
        }
+       $children_reaped++;
         if($Global::sshmaster{$stiff}) {
             # This is one of the ssh -M: ignore
             next;
@@ -4112,12 +4111,12 @@ sub reaper {
             }
         }
        $job->cleanup();
-       start_more_jobs();
        if($opt::progress) {
            my %progress = progress();
            ::status_no_nl("\r",$progress{'status'});
        }
     }
+    if($children_reaped) { start_more_jobs(); }
     $opt::sqlmaster and $Global::sql->run("COMMIT;");
     debug("run", "done ");
     return wantarray ? @pids_reaped : $children_reaped;
_

短期間の仕事がたくさんある場合、これにはパフォーマンスがいくらかかかる可能性があります。いくら測定していません。

問題の他の部分は、GNU Parallelでの設計上の決定によるものです。

GNU Parallelは、ダイヤモンド演算子(<>)を使用して読み取られます。これにより、続行する前に1行が読み取られます。_(sleep 20)_からの読み取りでは、sleepが終了した後にのみファイルの終わりが生成されます。 、したがって、sleepが終了するまでブロックします。

したがって、GNU Parallelが最後のバイトを読み取るとき、これが実際にファイルの終わりであることを検出するために、sleepが終了するのを待つ必要があります。

デザインのその部分を変更する簡単な方法はありません。

幸い、dateを実行するとわかるように、これによってジョブの実行がブロックされることはありません。ジョブはすぐに開始されます。sleepを待機しているのは出力だけです。

_(seq 20; sleep 5) | parallel -j10  -k 'date;echo'
_

言い換えれば、あなたの問題は_-N2_とは関係ありません。ここでは問題を確認できません。

_(printf '%s\0' {1..4}; sleep 2) | parallel --null -k --lb -N 2 echo {1} {2}
_

しかし、あなたはcanここで問題を確認します。これは、最後の4〜8個の要素の前で一時停止します。

_(printf '%s\0' {1..40}; sleep 2) | parallel -j4 --null -k --lb -N 2 echo {1} {2}
_

これは、最後の8〜10個の要素の前で一時停止します。

_(printf '%s\0' {1..40}; sleep 2) | parallel -j8 --null -k --lb -N 2 echo {1} {2}
_

dateを実行すると、問題はジョブの開始ではなく、印刷を延期しているだけであることがわかります。

_(printf '%s\0' {1..40}; sleep 2) | parallel -j4 --null -k --lb -N 2 'date;'echo {1} {2}
_
1
Ole Tange