异常逃避Perl' eval'块

时间:2016-06-14 16:07:50

标签: perl eval lwp

我有一个Perl脚本可以自动从各种来源下载内容。它使用evalalarm块中进行下载,以便在需要的时间过长时尝试超时:

eval {
    alarm(5);
    my $res = $ua->request($req);
    $status = $res->is_success;
    $rawContent = $res->content;    
    $httpCode = $res->code;
    alarm(0);       
};

这已经工作了多年,但在做了一些系统更新之后,它突然停止工作。相反,它击中的第一个源超时,我得到以下错误,程序终止:

 Alarm clock

我做错了什么阻止eval突然发现警报?

1 个答案:

答案 0 :(得分:6)

SIGALRM的默认设置是终止程序,因此您需要处理它。一种常见的方法是在捕获SIGALRM时发出die,将其变为异常,即eval - 编辑。

eval {
    local $SIG{ALRM} = sub { die "Timed out" };
    alarm(5);
    my $res = $ua->request($req);
    $status = $res->is_success;
    $rawContent = $res->content;    
    $httpCode = $res->code;
    alarm(0);       
};
if ($@ and $@ !~ /Timed out/) { die }  # re-raise if it is other error

来自Signals in perlipc

  

信号处理也用于Unix中的超时,虽然在eval{}块内安全保护,但您可以设置一个信号处理程序来捕获警报信号,然后安排在一定时间内将信号传送给您。然后尝试阻止操作,在完成后清除警报,但在退出eval{}阻止之前清除警报。如果它关闭,你将使用die()跳出块,就像你在其他语言中使用longjmp()或throw()一样。

至于它是如何工作的,我能想到的一件事是eval中使用的包有自己的定时器,基于alarm,因此取消了你的alarm。来自alarm

  

一次只能计算一个计时器。每次调用都会禁用前一个定时器,并且可以提供一个参数0来取消之前的定时器而不启动新的定时器。

他们可能在超时时抛出异常并且您有预期的行为。此更新中的包行为已更改,现在您的警报正常工作并需要处理。当然,这是猜测。