假设使用以下代码创建句柄:
use IO::File;
my $fh = IO::File->new;
my $pid = $fh->open('some_long_running_proc |') or die $!;
$fh->autoflush(1);
$fh->blocking(0);
然后用这样的循环读取:
while (some_condition_here) {
my @lines = $fh->getlines;
...
sleep 1;
}
如果管道另一端的进程终止,我将some_condition_here
作为假设返回false?
$fh->eof
的测试不起作用,因为该过程仍然可以在不打印任何新行的情况下运行。对$fh->opened
的测试似乎没有任何用处。
目前我正在使用$pid =! waitpid($pid, WNOHANG)
,它似乎适用于符合POSIX标准的环境。这是最好的方法吗?在Windows上怎么样?
答案 0 :(得分:5)
使用select
,
use strict;
use warnings;
use IO::Select qw( );
sub process_msg {
my ($client, $msg) = @_;
chomp $msg;
print "$client->{id} said '$msg'\n";
return 1; # Return false to close the handle.
}
my $select = IO::Select->new();
my %clients;
for (...) {
my $fh = ...;
$clients{fileno($fh)} = {
id => '...'
buf => '',
# ...
};
$select->add($fh);
}
while (my @ready = $select->can_read) {
for my $fh (@ready) {
my $client = $clients{ fileno($fh) };
our $buf; local *buf = \( $client->{buf} );
my $rv = sysread($fh, $buf, 64*1024, length($buf));
if (!$rv) {
if (defined($rv)) {
print "[$client->{id} ended]\n";
} else {
print "[Error reading from $client->{id}: $!]\n";
}
print "[Incomplete message received from $client->{id}]\n"
if length($buf);
delete $clients{ fileno($fh) };
$select->remove($fh);
next;
}
while ($buf =~ s/^(.*\n)//) {
if (!process_msg($client, "$1")) {
print "[Dropping $client->{id}]\n";
delete $clients{ fileno($fh) };
$select->remove($fh);
last;
}
}
}
}
答案 1 :(得分:2)
等待实际的EOF有什么问题?
while (<$fh>) {
...
sleep 1;
}
你已经设置了非阻塞读取的句柄,所以它应该做正确的事情。实际上,根据你的例子,你甚至不需要设置非阻塞并且可以摆脱睡眠。
等some_long_running_proc
时还有其他想做的事情吗?如果是这样,select
可能就在您的未来。
答案 2 :(得分:2)
有很多选择。
readline
aka <$fh>
将在eof(或错误)上返回false。
eof
将在eof上返回true。
read
(块大小> 0)将在eof上返回已定义和零。
sysread
(块大小> 0)将在eof上返回已定义和零。
您可以使用select
或在上述任何操作之前使句柄无阻塞,以便无阻塞地进行检查。
答案 3 :(得分:1)
您可以使用select()来确定是否有任何数据或异常情况,例如关闭。
我个人更喜欢使用IO :: Multiplex,特别是在你从多个不同描述符复用输入的情况下,但在这种情况下可能不适用。