我有一个perl脚本,它一直作为守护进程循环运行.我想在perl脚本中运行一个基于时间(或计时器)的子函数,所以每运行2小时它会运行该子函数并继续它的循环.我正在考虑获取纪元时间,只是通过循环检查它几次,一旦它超过2小时就会运行子功能.在perl中有更好的方法吗?
谢谢,
LF4
解决方法
这取决于自上次子程序启动开始以来或自上次执行结束以来是否应该有2个小时.
1)如果后者(运行最后一个子程序结束和新程序开始之间的2小时),cespinoza的解决方案是完全可以接受的(无限循环,并调用sleep(7200);执行子程序后).
my $timeout = 7200; while (1) { dostuff(); sleep($timeout); };
唯一的问题是它无法处理dostuff()永远占用的情况,例如:陷入困境 – 讨论为什么这是一个重要的考虑因素和解决方法,见下文.
2)如果是前者(起点之间2小时),则有三个选项,与处理超过2小时[0]的子程序运行时有关.您在下面详细解释的3个选项是:
2a)启动一个新的子程序,而旧的子程序继续运行(并行);
2b)在旧子程序结束后启动新的子程序;
2c)启动一个新的子程序但首先停止执行前一个子程序.
2a 2c选项要求您将alarm()
设置为2小时,并且在触发警报时会发生什么不同.
[0]注意:由于任何子程序可能至少需要来自PC的一些资源,因此它总是 – 但是很小 – 它可能会超过2小时,所以你必须选择其中一个选项来处理这种情况.
2a)每2小时开始一次,如果没有完成则与旧执行并行运行.
该选项基本上是实现cron功能.
无论何时你听到并行这个词,你都可能会分开这个过程.
my $timeout = 7200; while (1) { # Not tested! eval { local $SIG{ALRM} = sub { die "alarm\n" }; if (!defined($child_pid = fork())) { die "cannot fork: $!\n"; } elsif (!$child_pid) { # Child dostuff(); exit; } # Parent continues to sleep for 2 hours alarm $timeout; # You need it in case forking off take >2hrs sleep; # forever }; die unless $@ eq "alarm\n"; # propagate unexpected errors # We don't need to check if $@ is true due to forever sleep }
2b)每2小时开球,如果旧的没有完成,让它一直运行直至完成
这可以重新措辞为“启动任务,如果它完成超过2小时,睡眠剩余”
my $timeout = 7200; while (1) { my $start = time; dostuff(); my $end = time; my $lasted = $end - $start; if ($lasted < $timeout) { sleep($timeout - $lasted); } };
2c)每两个小时开球,如果前一个没有完成,将它计时并杀死它
每当你看到这样的逻辑时,警报显然就是答案.
while (1) { my $finished = 0; eval { local $SIG{ALRM} = sub { die "alarm\n" }; alarm 7200; dostuff(); $finished = 1; sleep; # forever }; die unless $@ eq "alarm\n"; # propagate unexpected errors warn "Timed out!!!\n" unless $finished }
附:正如cespinoza指出的那样,你需要以某种方式守护脚本(确保它在你退出启动它的shell时不被杀死),通过Unix方式(例如将其作为nohup启动)或Perlish意味着(在Stackoverflow上搜索守护进程的Perl)对于那个的力学).