我正在开发一个带有测试套件的库,该套件使用Perl open
来运行它的测试。它看起来像这样:
open (MYOUT, "$myprog $arg1 $arg2 $arg3 2>&1 |") die "Bad stuff happened";
我真正想做的是衡量$myprog
的运行时间。不幸的是,只需抓住open
命令的开始时间和结束时间,就可以大致掌握启动过程所需的时间。
是否有某种方法可以强制open
命令完成整个过程(因此可以准确地测量时间),或者是否有其他方法可以完成同样的事情?
关键限制是我们需要捕获(可能很多)STDOUT
和STDERR
。
答案 0 :(得分:2)
由于您打开了一个管道,您需要在open
之前的时间至少在阅读之后
use warnings;
use strict;
use Time::HiRes qw(gettimeofday tv_interval sleep);
my $t0 = [gettimeofday];
open my $read, '-|', qw(ls -l) or die "Can't open process: $!";
while (<$read>)
{
sleep 0.1;
print;
}
print "It took ", tv_interval($t0), " seconds\n";
# close pipe and check
或者,为了计算整个过程,在管道上调用close
之后( 完成所有阅读后)
my $t0 = [gettimeofday];
open my $read, '-|', qw(ls -l) or die "Can't open process: $!";
# ... while ($read) { ... }
close $read or
warn $! ? "Error closing pipe: $!" : "Exit status: $?";
print "It took ", tv_interval($t0), " seconds\n";
close阻止并等待程序完成
关闭管道还会等待管道上执行的进程退出 - 如果您希望之后查看管道的输出 - 并隐式将该命令的退出状态值放入
$?
[...]
状态检查请参阅$? variable in perlvar和system
如果定时程序以阻塞的方式分叉并且不对其子女进行wait
,则不会正确计时。
在这种情况下,您需要识别他们使用的资源(文件?)并监控它。
我想补充一点,外部命令应该小心放在一起,以避免shell注入问题。一个好的模块是String::ShellQuote。例如,请参阅this answer和this answer
使用模块捕获流可以让您从shell中解脱出来,并可能打开其他方式来运行并更可靠地计时。一个好的是Capture::Tiny(还有其他的)。
感谢HåkonHægland的评论。感谢ikegami让我直截了当,使用close
(而不是waitpid
)。