我该如何指定Perl系统调用的超时限制?

27

有时我的系统调用会进入一个永久的状态。为了避免这种情况,我希望能够在指定的时间后退出调用。

是否有一种方法可以为 system 指定超时限制?

system("command", "arg1", "arg2", "arg3");

我希望从Perl代码中实现超时,以便提高可移植性,而不是使用一些特定于操作系统的函数,比如ulimit。


1
这是一个重复的问题,我已经数不过来有多少了:https://dev59.com/4k3Sa4cB1Zd3GeqPuE45、https://dev59.com/kEvSa4cB1Zd3GeqPawCT、https://dev59.com/t3E95IYBdhLWcg3wKq2q、https://dev59.com/M0_Ta4cB1Zd3GeqPCJui、https://dev59.com/PUjSa4cB1Zd3GeqPGIvt 等等。 - Ether
4个回答

29
请参考alarm函数。下面是来自pod的例子:
eval {
    local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required
    alarm $timeout;
    $nread = sysread SOCKET, $buffer, $size;
    alarm 0;
};
if ($@) {
    die unless $@ eq "alarm\n";   # propagate unexpected errors
    # timed out
}
else {
    # didn't
}

CPAN上有一些模块可以更好地包装它们,例如:Time::Out

use Time::Out qw(timeout) ;

timeout $nb_secs => sub {
  # your code goes were and will be interrupted if it runs
  # for more than $nb_secs seconds.
};

if ($@){
  # operation timed-out
}

2
这似乎可以工作,但问题在于通过系统调用执行的命令将继续运行,即使父Perl进程已经死亡。有人知道如何获取由系统调用运行的进程ID /句柄,以便我们可以在Perl脚本结束之前杀死它吗? - antred
1
@antred - 要获取进程ID,您需要使用fork重写它,而不是使用system。请查看IPC::Cmd和IPC::Run等模块,以使此过程更加简便(在此上下文中)。 - draegtun

15

你可以使用IPC::Run的run方法代替system,并设置超时时间。


4
这个怎么样:

那么 System::Timeout 呢?

这个模块扩展了 system,允许在指定秒数后超时。

timeout("3", "sleep 9"); # timeout exit after 3 seconds

仅提供链接的答案在内容移动或更改时并不有用。在您的回答中包含相关部分的链接,以适应问题。 - miken32
1
欢迎提供潜在解决方案的链接,但请添加链接周围的上下文,以便其他用户了解它是什么以及为什么存在。在引用重要链接时,请始终引用最相关的部分,以防目标站点无法访问或永久离线。请注意,仅仅是一个外部网站链接可能是为什么和如何删除某些答案?的原因之一。 - FelixSFD

4

我之前在Perl + Linux中使用了timeout命令,你可以像这样测试一下:

for(0..4){
  my $command="sleep $_";  #your command
  print "$command, ";
  system("timeout 1.1s $command");  # kill after 1.1 seconds
  if   ($? == -1  ){ printf "failed to execute: $!" }
  elsif($?&127    ){ printf "died, signal %d, %scoredump", $?&127, $?&128?'':'no '}
  elsif($?>>8==124){ printf "timed out" }
  else             { printf "child finished, exit value %d", $? >> 8 }
  print "\n";
}

4.317秒后的输出结果:

sleep 0, child finished, exit value 0
sleep 1, child finished, exit value 0
sleep 2, timed out
sleep 3, timed out
sleep 4, timed out

timeout 命令是所有主要的“普通”Linux发行版(据我所知)的一部分,也是coreutils的一部分。


2
我不知道为什么这个答案没有更高的评价。在“运行系统调用”上下文中,使用系统解决方案似乎是合适的,而且简单直接。 - dennisjbell
非常适合“perl作为粘合代码”。谢谢。下次我写perl应用程序时,IPC::Run会得到尝试,但这正是我需要外壳时的情况。 - Bill McGonigle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接