Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在perl中以0.1s的精度在精确时间运行子例程_Perl - Fatal编程技术网

在perl中以0.1s的精度在精确时间运行子例程

在perl中以0.1s的精度在精确时间运行子例程,perl,Perl,需要每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(); } #!/usr/bin/perl use 5.014; use warnings; use Time::HiRes qw(tv_interval usleep gettim

需要每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();
}
#!/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)
}
run\u此
sub可以快也可以慢(运行时间在0.2-120秒之间)。当它运行超过5秒时-无论运行时间如何,下一次运行必须精确到5秒

例如,当
运行此

  • 11:11:12.3结束需要等待2.7秒才能在11:11:15进行下一次运行
  • 当在11:11:59.2结束时,只需等待0.8秒到下一个11:12:00,依此类推

问题是:如何编写do_sleep?

使用高精度计时器from Time::HiRes为循环计时

将长时间运行的作业放入后台进程

my $pid = fork;
die "fork failed" unless defined $pid;
if ($pid == 0) {
    # child process goes here
    run_this();
    exit;
}
# parent process continues here
另见

您可以使用Time::HiRes并计算这样等待的时间:

use Time::HiRes;
my $t = time();
my $nextCallTime = int($t) / 5 * 5 + 5;
my $timeToWait = $nextCallTime - $t;
sleep($timeToWait);

我没有测试代码,当调用恰好在5秒边界结束时,可能存在一些边界条件。但我认为它给出了正确的想法。

对于0.1s的精度,您需要使用Time::HiRes模块。比如:

for(;;) {
    do_sleep(); #time need to sleep to the next 5 second mark
    run_this();
}
#!/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)
}

如果您有信号处理程序,这个也可以使用。它还处理闰秒

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());
使用时间::雇佣qw();
子不间断\u睡眠\u直到{
我的($until)=@;
对于(;;){
我的$length=$until-Time::HiRes::Time();

最后,如果$length一个非常不同的方法将用于此。您可以为将来的特定时间安排一个事件。

如果
run\u this()
可能需要5秒以上的时间,则无法保证
run\u this()
将每5秒运行一次。无论如何,不会在单个线程中运行……如果
run\u this()
是线程安全的,那么您可以让线程启动
运行\u this()
每5秒一次。我的意思是在潜艇结束后不要睡5秒。因此,当运行时间为53.2秒时,睡1.8秒到下一个5秒标记。啊,好的。在这种情况下,jm666或Jim Corbett的答案都应该有效。你在做什么,需要这样的精度?可能有更好的方法来协调工作。T他
run_this
通过usb和微控制器做一些事情,细节只知道我们的硬件人员……(我希望比22:05:35.2341这样的开始时间意味着0.0002341秒。)讨厌的mili micro.:)谢谢。接受。@andras fekete,请发布您自己的答案。谢谢,我也会尝试。@kobame,经过测试。修复了一些小错误。@kobame,使用了DateTime的更轻的替代方案。特别是,您需要一个间隔5秒的
IO::Async::Timer::Periodic