需要每5秒运行一个子程序,但是在系统时钟标记处测量。因此,需要开始每分钟0,5,10,15 ...... 45,50,55秒(确切地说,精确度为0.1秒)。
类似的东西:
for(;;) {
do_sleep(); #time need to sleep to the next 5 second mark
run_this();
}
run_this
sub可以快或慢(其运行时间在0.2 - 120秒之间)。当它运行超过5秒时 - 无论其运行时间如何,下一次运行必须精确到5秒。
E.g。何时run_this
问题是:如何编写do_sleep?
答案 0 :(得分:5)
对于0.1s精度,您需要使用Time :: HiRes模块。类似的东西:
#!/usr/bin/perl
use 5.014;
use warnings;
use Time::HiRes qw(tv_interval usleep gettimeofday);
for(;;) {
do_sleep();
run_this();
}
sub do_sleep {
my $t = [gettimeofday];
my $next = (int($t->[0]/5) + 1) * 5;
my $delta = tv_interval ($t, [$next, 0]);
usleep($delta * 1_000_000);
return;
}
sub run_this {
my $t = [gettimeofday];
printf "Start is at: %s.%s\n",
scalar localtime $t->[0],
$t->[1];
usleep( rand 10_000_000 ); #simulating the runtime between 0-10 seconds (in microseconds)
}
答案 1 :(得分:2)
如果您有信号处理程序,这个也可以。它还处理闰秒。
use Time::HiRes qw( );
sub uninterruptible_sleep_until {
my ($until) = @_;
for (;;) {
my $length = $until - Time::HiRes::time();
last if $length <= 0;
Time::HiRes::sleep($length);
}
}
sub find_next_start {
my $time = int(time());
for (;;) {
++$time;
my $secs = (localtime($time))[0];
last if $secs % 5 == 0 && $secs != 60;
}
return $time;
}
uninterruptible_sleep_until(find_next_start());
请注意,系统可能不会在您需要时提供时间片,因此您实际上可能会比请求时间晚开始。
答案 2 :(得分:2)
一种非常不同的方法是使用IO::Async。您可以在将来的某个特定时间安排活动。
答案 3 :(得分:1)
使用Time :: HiRes中的高精度定时器来定时循环
http://perldoc.perl.org/Time/HiRes.html
将您的长期工作纳入后台流程
my $pid = fork;
die "fork failed" unless defined $pid;
if ($pid == 0) {
# child process goes here
run_this();
exit;
}
# parent process continues here
答案 4 :(得分:1)
您可以使用Time :: HiRes并计算等待多长时间:
use Time::HiRes;
my $t = time();
my $nextCallTime = int($t) / 5 * 5 + 5;
my $timeToWait = $nextCallTime - $t;
sleep($timeToWait);
我没有测试代码,当调用在5秒的边界完成时可能会有一些边界条件。但我认为它给出了正确的想法。