perl filehandle while 循环不会在没有更多行时终止
perl filehandle while loop does not terminate on no further lines
以下设置:
linux debian based 4.4.14-v7+ armv7l GNU/Linux
perl version is v5.20.2 built for arm-linux-gnueabihf-thread-multi-64int
一个应该读取数据流的 Perl 脚本(十六进制字符,每行不同长度)
示例流输出:
00 AA BB 11 22 33 44 ...
00 AB BB 11 22 33 44 ...
根据特定值,脚本应执行特定操作。
工作正常但是当流停止发送数据时,即流完成发送数据时,while 循环不会停止。并且脚本等待更多行。
流本身发送 f.e。 5 秒的数据,然后分析脚本应该 do_stuff;
一旦分析脚本完成计算,它将再次启动流。
但是我无法弄清楚为什么 "next command" 没有被执行,或者 while 循环没有在更多行上正确终止。
如果我再次手动启动流处理,分析脚本会继续正常运行,直到不再有更多的行。
简化代码
#!/usr/bin/perl
#script to analyse data
use warnings;
use strict;
use POSIX ();
sub stop_stream($){
my $pid = shift;
my $cmd = "/bin/kill -9 $pid";
system($cmd);
}
while (1){
my $steampid = open( STREAM, "/usr/local/bin/stream |" );
STREAM: while ( my $row = <STREAM> ) {
chomp $row;
my @o = split /\s+/, $row;
#do_stuff;
#..
#this is the row on which the script hangs until it get's new lines in the filehandle.
next STREAM if $o[1] ne "AA";
#...
#do_other_stuff;
#...
}
stop_stream( $steampid );
close STREAM;
}
我试图找出问题的资源:
http://perldoc.perl.org/perlsyn.html#Compound-Statements
http://www.perlmonks.org/?node_id=1065701
和许多其他人。
我尝试将 Whosebug 与 "perl while loop close filehandle" 的某种组合结合使用,但没有成功。
OK,问题的根源在于,如果文件句柄是open,但没有数据可读,while ( <FILEHANDLE> ) {
循环会阻塞。
因此 /usr/local/bin/stream
可能会继续传输数据直到被杀死 - 因此您的读取会阻塞。
简单的解决方案是使用类似 IO::Select
的东西,其中有 can_read
作为选项:
use IO::Select;
open ( my $stream, '-|', '/usr/local/bin/stream' ) or die $!;
#register this filehandle with a new select object
my $select = IO::Select -> new ( $stream );
#2s stream timeout.
#works because can_read returns a list of filehandles ready for reading
#with only one filehandle registered, it can be used as a simple logic test.
while ( $select -> can_read(2) ) {
my $row = <$stream>;
#etc.
}
#etc.
以下设置:
linux debian based 4.4.14-v7+ armv7l GNU/Linux
perl version is v5.20.2 built for arm-linux-gnueabihf-thread-multi-64int
一个应该读取数据流的 Perl 脚本(十六进制字符,每行不同长度) 示例流输出:
00 AA BB 11 22 33 44 ...
00 AB BB 11 22 33 44 ...
根据特定值,脚本应执行特定操作。 工作正常但是当流停止发送数据时,即流完成发送数据时,while 循环不会停止。并且脚本等待更多行。
流本身发送 f.e。 5 秒的数据,然后分析脚本应该 do_stuff;
一旦分析脚本完成计算,它将再次启动流。
但是我无法弄清楚为什么 "next command" 没有被执行,或者 while 循环没有在更多行上正确终止。
如果我再次手动启动流处理,分析脚本会继续正常运行,直到不再有更多的行。
简化代码
#!/usr/bin/perl
#script to analyse data
use warnings;
use strict;
use POSIX ();
sub stop_stream($){
my $pid = shift;
my $cmd = "/bin/kill -9 $pid";
system($cmd);
}
while (1){
my $steampid = open( STREAM, "/usr/local/bin/stream |" );
STREAM: while ( my $row = <STREAM> ) {
chomp $row;
my @o = split /\s+/, $row;
#do_stuff;
#..
#this is the row on which the script hangs until it get's new lines in the filehandle.
next STREAM if $o[1] ne "AA";
#...
#do_other_stuff;
#...
}
stop_stream( $steampid );
close STREAM;
}
我试图找出问题的资源:
http://perldoc.perl.org/perlsyn.html#Compound-Statements
http://www.perlmonks.org/?node_id=1065701
和许多其他人。
我尝试将 Whosebug 与 "perl while loop close filehandle" 的某种组合结合使用,但没有成功。
OK,问题的根源在于,如果文件句柄是open,但没有数据可读,while ( <FILEHANDLE> ) {
循环会阻塞。
因此 /usr/local/bin/stream
可能会继续传输数据直到被杀死 - 因此您的读取会阻塞。
简单的解决方案是使用类似 IO::Select
的东西,其中有 can_read
作为选项:
use IO::Select;
open ( my $stream, '-|', '/usr/local/bin/stream' ) or die $!;
#register this filehandle with a new select object
my $select = IO::Select -> new ( $stream );
#2s stream timeout.
#works because can_read returns a list of filehandles ready for reading
#with only one filehandle registered, it can be used as a simple logic test.
while ( $select -> can_read(2) ) {
my $row = <$stream>;
#etc.
}
#etc.