简体   繁体   English

根据时间在perl脚本中运行sub?

[英]Run a sub in a perl script based on the time?

I have a perl script that runs as a daemon looping all the time. 我有一个perl脚本,它一直作为守护进程循环运行。 I want to run a subfunction in a perl script that is based on the time (or timer) so every 2hrs it would run that subfunction and continue with it's loop. 我想在perl脚本中运行一个基于时间(或计时器)的子函数,所以每运行2小时它会运行该子函数并继续它的循环。 I'm thinking getting the epoch time and just checking it a few times through the loop and once it's greater then 2hrs it runs the subfunction. 我正在考虑获取纪元时间,只是通过循环检查它几次,一旦它超过2小时它运行子功能。 Is there a better way to do this in perl? 在perl中有更好的方法吗?

Thanks, 谢谢,
LF4 LF4

This depends on whether there should be 2 hours since the START of the last subroutine launch, or since the END of last execution. 这取决于自上次子程序启动开始后应该有2个小时,还是自上次执行结束以来。


1) If the latter (2 hours between the end of running the last subroutine and the start of new one), cespinoza's solution is perfectly acceptable (loop infinitely, and call sleep(7200); after executing the subroutine). 1)如果后者(运行最后一个子程序结束和新程序开始之间的2小时),cespinoza的解决方案是完全可以接受的(无限循环,并调用sleep(7200);执行子程序后)。

my $timeout = 7200;
while (1) {
    dostuff();
    sleep($timeout);
};

The only problem with this is that it can't handle the case where dostuff() takes forever, eg gets stuck - for the discussion of why it's an important situation to consider and approaches to solve, see below. 唯一的问题是它无法处理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] . 2)如果是前者(起点之间2小时),则有三个选项,与处理超过2小时[0]的子程序运行时有关。 Your 3 options, explained in detail below, are to either: 您在下面详细解释的3个选项是:

2a) kick off a new subroutine while the old one keeps running (in parallel); 2a)启动一个新的子程序,而旧的子程序继续运行(并行);

2b) to kick off a new subroutine AFTER the old one finishes; 2b)在旧子程序结束后启动新的子程序;

2c) to kick off a new subroutine but first stop the execution of the prior one. 2c)启动一个新的子程序但首先停止执行前一个子程序。

2a an 2c options require you to set an alarm() for 2 hours, and differ in what happens when an alarm gets triggered. 2a 2c选项要求您设置alarm() 2小时,并且在触发警报时会发生什么不同。

[0] NOTE: since any subroutine is likely to require at least SOME resources from the PC, there's always a - however small - chance that it would exceed 2 hours, so you have to pick one of those 3 options to handle such a scenario. [0]注意:由于任何子程序可能至少需要来自PC的一些资源,因此它总是 - 但是很小 - 它可能会超过2小时,所以你必须选择其中一个选项来处理这种情况。


2a) Kick off every 2 hours, running in parallel with old execution if not finished. 2a)每2小时开始一次,如果没有完成则与旧执行并行运行。

This option is, essentially, implementing cron functionality. 该选项基本上是实现cron功能。

Anytime you hear the word parallel, you would likely fork off the process. 无论何时你听到并行这个词,你都可能会把这个过程分开。

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) Kick off every 2 hours, if the old one didn't finish, let it run till it finishes 2b)每2小时开球,如果旧的没有完成,让它一直运行直至完成

This can be re-worded as "kick off task, if it finishes faster than 2 hours, sleep for the remainder" 这可以重新措辞为“启动任务,如果它完成超过2小时,睡眠剩余”

my $timeout = 7200;
while (1) {
    my $start = time;
    dostuff();
    my $end = time;
    my $lasted = $end - $start;
    if ($lasted < $timeout) {  
        sleep($timeout - $lasted);
    }
};

2c) Kick off every two hours, if the previous one didn't finish, time it out and kill it 2c)每两个小时开球,如果前一个没有完成,将它计时并杀死它

Whenever you see logic like this, alarm is obviously the answer. 每当你看到这样的逻辑时,警报显然就是答案。

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
}

PS As cespinoza noted, you need to somehow daemonize the script (ensure it doesn't get killed when you exit the shell that started it), by either Unix means (eg launching it as nohup) or Perlish means (search for daemonize + Perl on Stackoverflow for mechanics of that). PS正如cespinoza所指出的,你需要以某种方式守护脚本(确保它在你退出启动它的shell时不被杀死),通过Unix方式(例如将其作为nohup启动)或Perlish意味着(搜索daemonize + Perl)在Stackoverflow上的力学)。

Something like crontab would be best to do a timed job like that. 像crontab这样的东西最好做那样的定时工作。 However, if you want to run a Perl daemon, you'll have to use some kind of event handler. 但是,如果要运行Perl守护程序,则必须使用某种事件处理程序。 Two choices off the top of my head are POE and AnyEvent . 我最AnyEvent两个选择是POEAnyEvent

您可能需要检查Schedule :: Cron以进行任务规划和执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM