这取决于自上次子例程启动的 START 或自上次执行的 END 以来是否应该有 2 小时。
1) 如果是后者(在运行最后一个子程序结束和开始新子程序之间的 2 小时),cespinoza 的解决方案是完全可以接受的(无限循环,并在执行子程序后调用sleep(7200);)。
my $timeout = 7200;
while (1) {
dostuff();
sleep($timeout);
};
唯一的问题是它无法处理dostuff() 永远占用的情况,例如卡住了 - 关于为什么这是一个需要考虑的重要情况和解决方法的讨论,请参见下文。
2) 如果是前者(起点之间的时间为 2 小时),您有 3 个选项,涉及处理超过 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
}
附:正如 cespinoza 所指出的,您需要通过 Unix 方式(例如,以 nohup 启动它)或 Perlish 方式(搜索 daemonize + Perl on Stackoverflow 的机制)。