重要な出力が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);
}
プロセスをシャットダウンする前に、読み取りを終了してください。プロセスのstdinに書き込んでいる場合は、上記のselectループに$wtrとsyswriteも追加する必要があります。
編集
理論的根拠:
上記は、単純なケースではおそらくやり過ぎです。この入力と出力の高度な処理は、数Kを超えるデータを移動する可能性が高い場合に役立ちます。
たとえば、「df」コマンドを実行している場合は必要ありません。
ただし、stdin、stdout、またはstderrのいずれかのシステムバッファがいっぱいになると、ブロックが発生する可能性が高くなり、事態がさらに複雑になる可能性があります。
子プロセスがstderrおよび/またはstdoutバッファーをいっぱいにすると、ブロックされ、それらがクリアされるのを待つ可能性があります。ただし、stdoutまたはstderrから読み取る前にプロセスが終了するのを待っている場合は、それはデッドロックです。システムコールが終了せず、子プロセスが完了しないことがわかります。
stdinが書き込まれている場合、同様のデッドロックの可能性がありますが、子プロセスは入力を消費できません。これは、子プロセスが入力とstdoutへの書き込みを消費している「パイプ」状況で特に発生する可能性があります。
選択ループは、ブロッキングを回避するためにバッファを段階的にクリアすることです。stdoutとstderrの両方が同時に監視されます。
stdinに書き込み、stdout(パイプ)から読み取る場合は、stdoutとstderrをクリアに保ち、入力を受け取る準備ができたときにのみstdinに書き込む必要があります。
プロセスが終了するのを待つだけで、stdout / stderrの読み取りはおそらく90%の時間で機能します。この返信は、事態がさらに複雑になり、プロセスがブロックされ始めたり、デッドロックに陥ったりした場合に、どこかに行くための場所を提供するためのものです。
EDIT2
どちらを使うかというと、簡単に始めて、一生懸命テストすると思います。
Sorpigalのアプローチを採用しますが、データ量が多く、実際のシステムで予想されるより困難な負荷と条件の下で、ストレステストを試してください。