Если значительный результат записывается в stdout и/или stderr, или вы оба читаете и записываете в процесс. Вы должны быть намного более осторожны с обработкой ввода-вывода, чтобы избежать различных проблем с блокировкой.
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 этого процесса, вам также необходимо добавить $ wtr и syswrite в цикл выше выбора.
EDIT
Обоснование:
выше, вероятно, избыточна для простых случаев. Эта расширенная обработка ввода и вывода вступает в игру, когда вы, вероятно, переместите более нескольких K данных.
Вам не понадобится, если вы выполняете команду «df», например.
Однако, когда системные буферы для любого из stdin, stdout или stderr заполняются, блокирование становится вероятным, и все может стать более привлекательным.
Если дочерний процесс заполняет буферы stderr и/или stdout, он, вероятно, блокирует и ждет вас, чтобы очистить их. Но если вы ожидаете завершения процесса, прежде чем читать с stdout или stderr; это тупик. Вероятно, вы увидите, что системный вызов никогда не заканчивается, и дочерний процесс никогда не завершается.
Существует аналогичная возможность блокировки, если записывается stdin, но дочерний процесс не может потреблять вход. Это особенно вероятно в ситуации «трубы», когда дочерний процесс потребляет вход и запись в стандартный вывод.
Цикл выбора - это постепенное очищение буферов, чтобы избежать блокировки. Оба stdout и stderr контролируются одновременно.
Если вы пишете на stdin и читаете на stdout (трубе), вы хотите, чтобы stdout и stderr были очищены и только записывались в stdin, когда он был готов к приему ввода.
Просто дожидаясь завершения процесса, чтение stdout/stderr возможно работает в 90% случаев. Этот ответ - просто дать вам куда-то пойти, если ситуация усложнится, и процессы начинают блокироваться или заходить в тупик.
EDIT2
Как для которого использовать, я бы сказал, начать простой, тест трудно.
Пойдите с подходом Sorpigal, но попробуйте подчеркнуть тест с более высокими объемами данных и при более сложных нагрузках и условностях, которые вы когда-либо ожидали в живой системе.
+1 для предоставления как ссылки в документе Perl, так и предоставления ответа. – 2010-12-07 16:02:38
Копирование/вставка документации для удовольствия и прибыли ... – Sorpigal 2010-12-07 17:13:02