重要な出力がstdoutおよび/またはstderrに書き込まれている場合、またはそのプロセスに対して読み取りと書き込みの両方を行っている場合。さまざまなブロッキングの問題を避けるためには、I/O処理にもっと注意する必要があります。
my ($wtr, $rdr, $err) ;
my $pid = IPC::Open3::open3($wtr, $rdr, $err, @_);
close($wtr);
my $stdout = '';
my $stderr = '';
my $s = IO::Select->new;
$s->add($rdr) if $rdr;
$s->add($err) if $err;
while (my @ready = $s->can_read) {
foreach my $ioh (@ready) {
my $bytes_read = sysread($ioh, my $chunk = '', 1024);
die "read error: $!" unless $bytes_read >= 0;
if ($bytes_read) {
($ioh eq $rdr? $stdout: $stderr) .= $chunk;
}
else {
$s->remove($ioh);
}
}
}
my $pid1;
for (;;) {
last if kill(0, $pid);
$pid1 = wait();
#
# Wait until we see the process or -1 (no active processes);
#
last if ($pid1 == $pid || $pid1 <= 0);
}
プロセスをシャットダウンする前に読み終えてください。プロセスの標準に書いている場合は、上記のselectループに$ wtrとsyswriteを追加する必要があります。
EDIT
理由:
上記のは、おそらく単純な場合のためにやり過ぎです。この高度な入出力処理は、数Kを超えるデータを移動する可能性が高い場合に有効です。
たとえば、 'df'コマンドを実行していた場合は必要ありません。
しかし、stdin、stdout、またはstderrのいずれかのシステムバッファがいっぱいになると、ブロックする可能性が高くなり、状況がより複雑になることがあります。
子プロセスがstderrおよび/またはstdoutバッファをいっぱいにすると、ブロックされ、それらをクリアする可能性があります。しかし、stdoutまたはstderrから読み込む前にプロセスの終了を待っている場合は、デッドロックです。システムコールが終了せず、子プロセスが完了しないことが分かります。
stdinに書き込まれているにもかかわらず、子プロセスが入力を消費できない場合、同様のデッドロックの可能性があります。これは、子プロセスが入力とstdoutへの書き込みを消費している 'パイプ'の状況で特にそうです。
selectループでは、ブロッキングを回避するためにバッファが徐々にクリアされています。 stdoutとstderrの両方が同時に監視されます。
stdoutに書き込んでstdout(パイプ)から読み込む場合は、stdoutとstderrをクリアにし、入力を受け取る準備ができたらstdinに書き込むだけです。
プロセスが終了するのを待つだけで、stdout/stderrを読むのはおそらく時間の90%で行われます。この返信は、状況がより複雑になり、プロセスがブロックされたりデッドロックに陥ったりすると、どこかに行くことができます。私が言うと思います使用するためのEDIT2
は、ハード、単純な、テストを開始します。 Sorpigalのアプローチに従いますが、より高いデータ量と、実際のシステムで期待していたより困難な負荷と条件でストレステストを試みてください。
+1は、Perlのドキュメントで参照を与え、答えを提供します。 –
楽しいと利益のためにドキュメントをコピー/貼り付け... – Sorpigal
+1ありがとうございます。これを拡張して、 'test_app'の戻り値が有効であることを確認できますか?' capture([0]、...) 'のように' 0'ですか? –