windows和linux中的Perl超时命令



我正在编写一个需要在windows和linux中运行的perl脚本,该脚本将运行一个进程,如果时间过长,则超时,如果没有超时则返回退出代码,如果exitcode为零且没有超时则返回stdout。我不需要STDIN或STDERR。我试过使用IPC::run,但无法使用。

我得到的最接近的是IPC::Open3waitpid($pid, WNOHANG)。但我遇到了一个障碍。我在windows和linux上看到了不同的结果。在下面的代码中,我给open3一个将失败的命令(ping没有任何参数-z(。在linux上,代码会立即返回一个负退出代码。在windows中,命令超时。在windows命令行上运行ping google.com -z会立即返回,告诉我没有这样的参数。为什么`waitpid`返回零?

use strict;
use warnings;
use POSIX ":sys_wait_h";
use IPC::Open3;
my $inFH;
my $outFH;
my @cmd = ("ping", "google.com", "-z");
my $pid = open3( $inFH, $outFH, 0, @cmd);
my $counter=0;
my $waitret;
my $exitcode;
do{
$counter++;
$waitret = waitpid($pid,WNOHANG);   
$exitcode = $?;
}while( !$waitret and ($counter < 4_000_000));
if ($counter >= 4_000_000) {
print "Command timed outn";
kill(9, $pid);
} else {
print "Exit Code: $exitcoden";
}

欢迎其他解决方案。我在nohang中使用waitpid的唯一原因是,如果花费太长时间,就会终止进程。在此期间,我没有任何其他需要处理的事情。我使用的是windows 10草莓perl 5.28可在windows上移植。我的debian机器有perl5.24。

IPC::Run支持各种超时和定时器,它们也应该在Win32上工作。

基本:

use warnings;
use strict;
use feature 'say';
use IPC::Run qw(run timeout);
my $out;
eval {
run [ qw(sleep 20) ], undef, $out, timeout(2) or die "Can't run: $?"
};  
if ($@) { 
die $@ if $@ !~ /^IPC::Run: timeout/;
say "Eval: $@";
}

timeout抛出异常,因此eval抛出异常。还有其他计时器,其行为更加微妙和易于管理。请参阅文档。

如果捕获的异常不是由IPC::Run的计时器引起的,则会重新引发异常——这取决于我的系统上模块的版本在消息中打印的内容,该消息是一个以IPC::Run:timeout开头的字符串。请检查您的系统上有什么。

虽然有些东西在Windows上不起作用,但我认为计时器应该起作用。我现在不能测试。


据报道,虽然上述方法有效,但如果有一个更有意义的命令,SIGBREAK (21)会在超时时发出,一旦处理完毕,该过程就会保持不变。

在这种情况下,在处理程序中手动终止

use warnings;
use strict;
use feature 'say';
use IPC::Run qw(run harness timeout);
my $out;
my @cmd = qw(sleep 20);
my $h = harness @cmd, undef, $out, timeout(2);
HANDLE_RUN: {
local $SIG{BREAK} = sub {
say "Got $_[0]. Terminate IPC::Run's process";
$h->kill_kill;
};  
eval { run $h };  
if ($@) { 
die $@ if $@ !~ /^IPC::Run: timeout/;
say "Eval: $@";
}
};

为了能够在这里使用模块的kill_kill,我首先创建了线束,然后在安装处理程序时可以使用该线束,并且当它启动时可以在其上调用kill_kill

另一种方法是查找进程ID(使用Win32::进程::信息或Win32::过程::列表(,并使用kill、Win32::Process或TASKKILL终止它。请参阅本文(下半部分(。

一个块仅添加到local中—使信号处理程序大小。在实际代码中,所有这些都可能以某种方式确定范围,因此可能不需要额外的块。

请注意,Windows没有POSIX信号,Perl只模拟一些非常基本的UNIX信号,以及特定于Windows的SIGBREAK

最新更新