Я просто пытаюсь выяснить, как правильно использовать функцию open2
.
См. Пример ниже.Это работает для небольшого $max
, но, естественно, если я напишу достаточно долго в $hIn
, то в итоге он будет заблокирован, потому что ничто не читает данные на выходе непрерывно.
use 5.26.0;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
{
my $cnt = 0;
#When $max is big (e.g. 100000) so the code below will get blocked
#when writing to $hIn
while ($cnt<$max) {say $hIn $cnt++;}
close($hIn) || say "can't close hIn";
}
while(<$hOut>) { print; }
close($hOut) || say "can't close hOut";
waitpid( $pid, 0 );
ЕдинственноеРешение, о котором я могу подумать, - запустить другой поток, который будет писать в фоновом режиме.
С помощью приведенного ниже кода я могу записать в $hIn
столько данных, сколько захочу, и прочитать их восновной поток, но $hIn
, похоже, не закрывается.Из-за этого while(<$hOut>)
никогда не закончится в ожидании большего вывода.
use 5.26.0;
use threads;
use IPC::Open2;
my $max = 100000;
my $pid = open2(my $hOut, my $hIn, "cat") || die "failed 'cat': $!";
my $thr = threads->create(sub {
my $cnt = 0;
while ($cnt<$max) {say $hIn $cnt++;}
#The close does not have any effect here (although no error is produced)
close($hIn) || say "can't close hIn";
});
#This outputs all the data written to $hIn but never leaves the loop...
while(<$hOut> ) { print; }
close($hOut) || say "can't close hOut";
$thr->join;
waitpid( $pid, 0 );
Мои вопросы:
- При условии, что мой подход с потоками в порядке, как я могузакрыть дескриптор файла из фонового потока?
- Если это не так (на самом деле
use threads
не рекомендуется в Perl), так может кто-нибудь предоставить рабочий пример open2, который может писать и читать много данных безриск быть заблокированным в ожидании читателя или писателя?
РЕДАКТИРОВАТЬ: Следуя вашим рекомендациям, здесь приведена реализация приведенного выше кода с использованием IPC :: Run:
use 5.26.0;
use IPC::Run qw/ run /;
my $max = 1000000;
run sub {
my $cnt = 0;
while ($cnt<$max) {say $cnt++;}
},
"|", "cat",
"|", sub {
while(<> ) {
print;
}
}
or die "run sub | cat | sub failed: $?";
Он работает без ошибок, код очень удобочитаемый ... Я очень рад, что узнал об этом модуле.Спасибо всем!
Тем не менее, я считаю этот вопрос без ответа.Если невозможно написать эту функцию, используя open2
напрямую, почему это вообще существует и сбивает с толку людей?Также невозможность закрыть дескриптор файла из другого потока выглядит для меня как ошибка (конечно, это так - закрытие должно как минимум сообщать об ошибке).