这取决于自上次子例程启动开始或自上次执行结束以来是否应该有 2 小时。
1)如果是后者(运行最后一个子例程结束和新子例程开始之间有2小时),塞斯皮诺扎的解决方案是完全可以接受的(无限循环,并调用sleep(7200);
执行子程序后)。
my $timeout = 7200;
while (1) {
dostuff();
sleep($timeout);
};
唯一的问题是它无法处理以下情况dostuff()
需要永远,例如陷入困境 - 有关为什么这是需要考虑的重要情况以及解决方法的讨论,请参阅下文。
2) If the former (2 hours between starting points), you have three options, related to handling the subroutine run-time that exceeds 2 hours[0]. Your 3 options, explained in detail below, are to either:
2a) 启动一个新的子程序,同时旧的子程序继续运行(并行);
2b) 在旧子程序完成后启动新子程序;
2c) 启动一个新的子例程,但首先停止前一个子例程的执行。
2a 和 2c 选项要求您设置alarm() http://perldoc.perl.org/functions/alarm.html2 小时,并且触发警报时发生的情况有所不同。
[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 所指出的,您需要以某种方式对脚本进行守护进程(确保当您退出启动它的 shell 时它不会被杀死),通过 Unix 方式(例如以 nohup 启动它)或 Perlish 方式(在 on 上搜索 daemonize + Perl) Stackoverflow 的机制)。