如何告诉Perl每20秒运行一些代码?

时间:2010-09-20 07:07:22

标签: perl

如何告诉Perl每20秒运行一些代码?

8 个答案:

答案 0 :(得分:21)

for (;;) {
    my $start = time;
    # your code;
    if ((my $remaining = 20 - (time - $start)) > 0) {
        sleep $remaining;
    }
}

答案 1 :(得分:9)

while (1) {
        sleep 20;
        <your code here>;
}

答案 2 :(得分:8)

虽然sleep函数适用于某些用途,但如果您尝试“永远每20秒”执行一次,那么最好使用cron之类的外部实用程序。< / p>

除了已经提到的漂移问题之外,如果您的sleep脚本退出(预期或其他方式),那么它将不会在接下来的20秒标记处再次运行。

@Blrfl是对的,我感到羞怯。也就是说,它很容易克服。

* * * * * /path/to/script.pl
* * * * * sleep 20 && /path/to/script.pl
* * * * * sleep 40 && /path/to/script.pl

您还可以采用混合方法在脚本中放置一个有限计数的睡眠循环,并使用cron每隔X分钟运行一次,覆盖脚本死亡的情况。任何比20秒更频繁的事情,我肯定会接受这种方法。

答案 3 :(得分:7)

设置一个SIGALRM处理程序,并使用alarm每20秒发送一个信号(参见perldoc -f alarm):

$SIG{ALRM} = sub {
    # set up the next signal for 20 seconds from now
    alarm 20;

    # do whatever needs to be done
    # ...
};

随着时间的推移会出现漂移,因为每个信号可能会延迟一秒钟;如果这很重要,请改为设置一个cron作业。此外,如果您的其他代码运行时间超过20秒,则会发生更多漂移,因为只有一个计时器可以立即计数。你可以通过产生线程来解决这个问题,但是在这一点上,我已经回到了一个简单的cron解决方案。

选择正确的解决方案取决于您需要定期执行的任务类型,而您没有指定。

答案 4 :(得分:3)

请参阅Schedule::ByClock

#!/usr/bin/perl

use strict; use warnings;
use Schedule::ByClock;

my $scheduler = Schedule::ByClock->new(0, 20, 40);

while ( defined( my $r = $scheduler->get_control_on_second ) ) {
    printf "%02d\n", $r;
}

其他人指出的所有警告仍然适用,但我认为该模块很整洁。

答案 5 :(得分:2)

一起去..

while () {
  sleep 20;
  #Code here
}

答案 6 :(得分:2)

#!/usr/bin/perl -w

use strict;


# heartbeat
$SIG{ALRM} = sub {
    # set up the next signal for 20 second from now
    alarm(20);
    printf "<heartbeat/>\n";
};

alarm(20); # start timer
my $i = 0;
while(1) {
    $i++;
    printf "loop" . $i . "\n";
    sleep 2;
}

alarm(0);

printf "done!\n";

输出:

loop1
loop2
loop3
loop4
loop5
loop6
loop7
loop8
loop9
loop10
<heartbeat/>
loop11
loop12
loop13
loop14
loop15
loop16
loop17
loop18
loop19
loop20
<heartbeat/>

答案 7 :(得分:1)

最好使用一些事件库。有两种选择:

IO::Async::Timer::Periodic

use IO::Async::Timer::Periodic;

use IO::Async::Loop;
my $loop = IO::Async::Loop->new;

my $timer = IO::Async::Timer::Periodic->new(
   interval => 60,

   on_tick => sub {
      print "You've had a minute\n";
   },
);

$timer->start;

$loop->add( $timer );

$loop->run;

AnyEvent::DateTime::Cron

AnyEvent::DateTime::Cron->new()
    ->add(
        '* * * * *'   => sub { warn "Every minute"},
        '*/2 * * * *' => sub { warn "Every second minute"},
      )
    ->start
    ->recv

EV::timer