3

モジュールを見ていAnyEvent::Forkます。並行して (一度に 6 つ) 呼び出したい 20 個の外部スクリプトがあり、すべてが終了したら後でそれらの出力を要約します。これを達成する方法がわかりません。

モジュール内のサンプル コード (1 つの子のみを呼び出す) には問題があります。コードに単純なスリープを追加してすぐに戻らないようにするだけで、親は子プロセスを待たずにすぐに終了します。

open my $output, ">/tmp/log" or die "$!";

AnyEvent::Fork
   ->new
   ->eval ('
        # compile a helper function for later use
        sub run {
           my ($fh, $output, @cmd) = @_;

           # perl will clear close-on-exec on STDOUT/STDERR
           open STDOUT, ">&", $output or die;
           open STDERR, ">&", $fh or die;

           ### Added by me to demonstrate that
           ### $cv->recv returns immediately.
           sleep 5;

           exec @cmd;
        }
     ')
   ->send_fh ($output)
   ->send_arg ("/bin/echo", "hi")
   ->run ("run", my $cv = AE::cv);

my $stderr = $cv->recv;

その結果、それ/tmp/logは空です。ここでの使用方法condvarがわかりません。ドキュメントにはありません。を使用して実行中の子の数を取得できますcondvarか?

これを正しく行う方法を教えてください。

UPDATEここでの主な問題は、親が子が完了するのを待たないことです。

4

1 に答える 1

4

ここでの問題は、親と子が別々のプロセスであり、互いに独立して実行できるため、一方が他方を待つ必要がある場合は、明示的な同期が必要になることです。これには多くの方法がありますが、最も簡単な方法は、AnyEvent::Fork::RPC を使用して、子プロセスに「待機」リクエストを送信することです。子プロセスは、終了時に応答します。

裸の AnyEvent::Fork でこれを行うには、->run によって提供される双方向パイプを利用するのが最も簡単な方法です。

  AnyEvent::Fork
    ->new
    ->run (sub {
       my ($fh) = @_;
       sysread $fh, my $dummy, 1; # will wait for data, or eof
       ... done, you can now call e.g. $cv->send

sysread は子から読み取ろうとします。子が何も送信しない場合、これは子が終了するまで親をブロックします。その瞬間、子はパイプの終わりを閉じ、sysread は EOF を取得します。

もちろん、AnyEvent プログラムではおそらくブロックしたくないので、I/O ウォッチャーを使用します。

 ->run (sub {
    my ($fh) = @_;
    my $rw; $rw = AE::io $fh, 0, sub {
       ... read data received, or EOF
       undef $rw;
       ... done, you can now call e.g. $cv->send;
    }
  });

このトリックは、外部コマンドにも使用できます (この例では exec)。子のパイプのクローズオン exec 状態をクリアし、それを exec されたプログラムに渡します。この場合、すべてのプログラムがパイプ出口を継承する場合、パイプは EOF を通知します。

これで始められるはずです。他にも方法はありますが、良い方法のほとんどまたはすべては、通信用のパイプを必要とするものであり、取得する最も簡単な方法は、AnyEvent::Fork によって提供されるものを使用することです。

于 2014-11-30T23:34:02.010 に答える