Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: missing second of time

by tybalt89 (Parson)
on Jan 25, 2020 at 15:15 UTC ( #11111878=note: print w/replies, xml ) Need Help??


in reply to missing second of time

Don't sleep FOR one second, sleep until the NEXT second.

#!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11111868 use warnings; use Time::HiRes qw( time sleep ); while(1) { my $nextsecond = int time + 1; sleep $nextsecond - time; print time, "\n"; }

Outputs:

1579965143.0001 1579965144.00009 1579965145.00009 1579965146.00009 1579965147.0001 1579965148.0001 1579965149.00009 1579965150.0001 1579965151.0001 1579965152.00009 1579965153.00009 1579965154.0001 1579965155.00009 1579965156.00009 1579965157.00009 ...

Replies are listed 'Best First'.
Re^2: missing second of time
by LanX (Archbishop) on Jan 25, 2020 at 19:57 UTC
    yeah, the usual trick, but it it should be noted that because of the int the first sleep-interval will be far shorter than one second.

    DB<25> use Time::HiRes qw( time sleep ); DB<26> print time, "\n";$nextsecond = int time + 1;sleep $nextsecon +d - time;print time, "\n" 1579981231.91855 1579981232.00031 DB<27>

    Which is normally not a problem, if the loops body starts with the sleep, before doing something.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re^2: missing second of time
by Anonymous Monk on Jan 25, 2020 at 23:03 UTC
    Don't sleep FOR one second, sleep until the NEXT second.

    Thanks for the lightbulb. I see no error since doing it that way. I wonder if the perldoc for sleep should add something like:

      To delay ON each second, don't sleep FOR one second, sleep until the NEXT second, using sleep and time from Time::HiRes:

      Explain why this is a subtle trap:

      while () {
        print something();
        sleep 1 # WRONG!
      }
      
      Calculate the next second:
      use Time::HiRes qw/sleep time/;
      while () {
        print something();
        sleep do { (int time + 1) - time } # RIGHT!
      }
      
    Maybe it's already a FAQ? I don't know. Thank you!

      You are missing the conceptual loophole here.

      > print something();

      So what if something() takes longer than a second?

      Your sleep would just skip the missed steps till the following interval.

      The clean approach would be to include an exception handling.

      Apart from this could the OS be too busy to return in time, that's why sleep only guaranties minimal time.

      See Re: missing second of time

      > I wonder if the perldoc for sleep should add ...

      All these conditions might not be true in your case, but how do you want to include the general case in the docs???

      I think this use cases are best covered in a dedicated module.

      Update

      Might be interesting to compare how setInterval() in JS is handling those cases.

      Update

      From what I read after searching JS setInterval long running function it seems that delayed calls are queued to be executed later, and this without raising an exception. ... Ugly.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re^2: missing second of time
by Anonymous Monk on Feb 26, 2020 at 05:36 UTC
    Greeting monks, OP here. Thanks for all the input. I implemented tybalt89's solution (int time + 1) - time and the program ran for about a month until it crashed with this cool error:
    Time::HiRes::sleep(-0.202505): negative time not invented yet
    
    I don't know why that happened but I'm going to try tybalt's other solution at Re: missing second of time and see what happens... Peace, Love and Perl
      I tried the second solution with the fudge factor but it goes negative in less than an hour. I'll go back to the original suggestion and make sure the value is not negative before using it to sleep. Thanks again

        Try this one

        #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11111868 use warnings; use Time::HiRes qw( time sleep ); my $fudgefactor = 0.001; while(1) { my $time = time; my $nextsecond = int $time + 1; my $interval = $nextsecond - $time - $fudgefactor; $interval > 0 and sleep $interval; 1 while time < $nextsecond; printf "%.6f\n", time; }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://11111878]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chanting in the Monastery: (12)
As of 2020-04-01 08:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    To "Disagree to disagree" means to:









    Results (186 votes). Check out past polls.

    Notices?