我有一个perl脚本,它一直作为守护进程循环运行。我想在perl脚本中运行一个基于时间(或计时器)的子函数,所以每运行2小时它会运行该子函数并继续它的循环。我正在考虑获取纪元时间,只是通过循环检查它几次,一旦它超过2小时它运行子功能。在perl中有更好的方法吗?
谢谢,
LF4
答案 0 :(得分:9)
这取决于自上次子程序启动开始以来或自上次执行结束以来是否应该有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小时,所以你必须选择处理这种情况的3个选项之一。
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
}
P.S。正如cespinoza指出的那样,你需要以某种方式守护脚本(确保它在你退出启动它的shell时不被杀死),通过Unix方式(例如将其作为nohup启动)或Perlish意味着(搜索daemonize + Perl on Stackoverflow for mechanics of。)
答案 1 :(得分:2)
答案 2 :(得分:1)
您可能需要检查Schedule::Cron以查看任务计划和执行情况。