如何在Perl子例程調用上設置時間限制(應用超時處理)?如果運行時間太長,我想取消子程序。子程序可以調用C庫(例如,基於C的數據庫驅動程序),這意味着需要特殊處理。此外,SIGALRM可能已經在使用,所以我們不能直接使用alarm()。如何在Perl函數調用上超時
1
A
回答
0
下面是一些工作的代碼我從幾年前已經對處理這個問題:
our $signal_after_delay= "/path/to/signal_after_delay.pl"; # could be merged into code below
# execute a function call, but abort it if it takes too long to complete
# if a signal other than the default ALRM is given, assume that the function being called uses
# ALRMitself and use the given signal instead; for this case, we fork a child to give us the alternate
# signal at the time of the timeout
sub call_with_timeout {
my($desc,$fn,$args,$timeout,$verbosity,$sigtouse)= @_;
return undef unless defined($fn);
$timeout= 60 unless defined $timeout;
$verbosity= 1 unless defined $verbosity;
$sigtouse= 'ALRM' unless defined $sigtouse;
print "call_with_timeout(",join(',',$desc,$fn,'['.join(',',@{$args}).']',$timeout,$verbosity,$sigtouse),")\n" if $verbosity > 3;
my @res=();
my $start= time();
my $timeoutpid= undef;
eval {
my $sighandler= sub {0 && print "$$: in signal handler for $_[0]\n"; die "$$: $desc timed out with $_[0] after $timeout seconds" };
if ($sigtouse eq 'ALRM') {
alarm($timeout);
} else {
my $fncallingpid= $$;
$timeoutpid=fork();
if ($timeoutpid == 0) { # child
exec($signal_after_delay,$sigtouse,$fncallingpid,$timeout,$verbosity);
die "could not exec $signal_after_delay\n";
}
# parent
}
$SIG{$sigtouse}= $sighandler;
# on timeout, alarm handler above will execute and we'll fall out of this eval
# on normal exit, we'll fall out of the bottom of the eval with no error
print "$desc: starting call\n" if $verbosity > 1;
UNSAFE_SIGNALS {
# get signals immediately during this call rather than when Perl thinks it is a good time; this allows us to interrupt C routines such as VMware VIX
@res= &{$fn}(@{$args});
};
print "$desc exited normally: ",join(',',@res),"\n" if $verbosity > 2;
$SIG{$sigtouse}= 'IGNORE';
if ($sigtouse eq 'ALRM') {
alarm(0);
} else {
print "$$: canceling signal_after_delay.pl ($timeoutpid)\n" if $verbosity > 2;
kill 'KILL', $timeoutpid;
}
};
my $elapsed= time()-$start;
#print "waitpid($timeoutpid)\n" if defined($timeoutpid);
waitpid($timeoutpid,0) if defined($timeoutpid);
if ([email protected]) {
if ([email protected] =~ /timed out with/) { # we timed out
print "[email protected]\n";
return (0);
} else { # the method call did a die
# propagate
$SIG{$sigtouse}= 'IGNORE';
if ($sigtouse eq 'ALRM') {
alarm(0);
} else {
kill $timeoutpid;
}
die;
}
}
print qq{$desc exited normally [elapsed=$elapsed]\n} if $verbosity;
return (1,@res);
}
signal_after_delay.pl很簡單:
#!/usr/bin/perl -w
# send a given signal to a given PID after a given delay
use FileHandle;
STDOUT->autoflush(1);
my($sig,$targetpid,$wait,$verbosity)= @ARGV;
$wait= 60 unless defined($wait);
$verbosity= 1 unless defined($verbosity);
print "$0 ($$): will send SIG$sig to $targetpid after $wait seconds\n" if $verbosity > 1;
my $now= time();
my $end=$now+$wait;
do {
print "$$: will sleep for ",$end-$now,"\n" if $verbosity > 2;
sleep($end-$now);
$now= time();
} while ($now < $end);
print "$$: sending SIG$sig to $targetpid\n" if $verbosity;
kill $sig, $targetpid;
exit(0);
0
最簡單的答案是 - 用alarm
:) 。 但是,因爲這不是一種選擇,我提供的替代方案是使用線程來運行您可能想要殺死的代碼。
例如爲:
#!/usr/bin/perl
use strict;
use warnings;
use threads;
sub my_subroutine_to_timeout {
$SIG{'USR1'} = sub { print "Got USR1, dying\n"; die };
my $timeout = rand (30);
sleep ($timeout) ;
return $timeout;
}
my $thr = threads -> create (\&my_subroutine_to_timeout);
sleep 10;
if ($thr -> is_joinable()) {
my $result = $thr -> join();
print "Thread returned before timeout, with $result\n";
}
else {
print "Timeout: Killing\n";
$thr -> kill ('SIGUSR1'); #can trap with a signal handler.
$thr -> detach();
}
print "Main program continues, but may not have a result from the thread\n";
以上就是說明的 - 它是保證等待10秒的命令來完成,哪怕1秒後結束。但是有這方面的方法。
相關問題
- 1. 如何超時PowerShell函數調用
- 2. 如何從另一個PL/Perl函數調用PL/Perl函數?
- 3. Perl函數調用
- 4. C程序如何調用Perl函數?
- 5. 如何在超時後終止Perl系統調用?
- 6. 如何在Perl中調用調用localtime()的函數?
- 7. 如何在pyGTK超時中調用函數?
- 8. 如何在超時後調用函數功能完成?
- 9. 超時在Perl
- 10. ajax超時回調函數
- 11. 如何在調用javascript函數時調用gwt函數
- 12. Ruby on Rails調用perl腳本超時
- 13. 從Perl調用Javascript函數
- 14. Perl Win32 :: API()調用()函數
- 15. 函數調用無法評價超時
- 16. 如何爲Perl系統調用指定超時限制?
- 17. 如何在調用函數調用次數時調用函數中的閉包
- 18. 如何在onrowcommand上調用javascript函數?
- 19. 如何在GridView上調用applyFilter函數
- 20. 如何在MainActivity上調用ndk函數
- 21. C++:如何實現任意函數調用的超時?
- 22. 如何使函數調用之間的超時?
- 23. 太多的遞歸調用時調用函數(PARAMS)與超時
- 24. 在超鏈接上使用參數調用Js函數
- 25. 括號在Perl函數調用
- 26. 在perl中調用基構造函數
- 27. 在perl中調用函數的方法?
- 28. 如何在打印函數時調用
- 29. 在Apache/Perl下上傳超時問題
- 30. perl調整函數執行時間
答案應該解釋如何不同於'local $ SIG {ALRM} = sub {die「Timeout!\ n」};報警($ X); ...警報(0);' – ikegami 2014-08-31 14:25:00