Re: missing second of time
by tybalt89 (Monsignor) on Jan 25, 2020 at 15:15 UTC
|
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
...
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] |
|
|
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!
| [reply] |
|
|
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.
| [reply] [d/l] [select] |
|
|
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
| [reply] |
|
|
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
| [reply] |
|
|
Re: missing second of time
by choroba (Cardinal) on Jan 25, 2020 at 11:11 UTC
|
sleep says:
Most
modern systems always sleep the full amount. They may appear to
sleep longer than that, however, because your process might not be
scheduled right away in a busy multitasking system.
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
Re: missing second of time
by afoken (Chancellor) on Jan 25, 2020 at 19:03 UTC
|
First, sleep(), like any other system call, can be interrupted at any time.
(Beancounting: Yes, sleep() is technically no system call, but it uses system calls.)
That means that sleep(1) may actually return after just a few milliseconds. See also Signal to a sleeping Perl program.
Second, at any system call, you are returning control back to the operating system. And unless you run a real-time operating system, there are NO guarantees for when you get back control. Most times, it happens within milliseconds. But under heavy load, the operating system may decide that your process has to wait, and so you may get delays in the seconds range from start to end of a system call, and you will see jumps of several seconds.
Third, even without system calls, your programm will be forcefully interrupted and control returns forcefully to the operating system - unless you are running a real time operating system.
Fourth, if you need more or less exactly 1.000 s between function calls, don't use a function that has only 1 s resolution for timing. You want at least millisecond resolution. See previous postings by other monks.
So if you have hard real-time requirements, either use a real-time operating system, or run the timing-critical part on bare metal (e.g. on a microcontroller). See Re^2: Assembly language and Re^14: CPAN failed install for details.
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] |
Re: missing second of time
by tybalt89 (Monsignor) on Jan 25, 2020 at 17:19 UTC
|
#!/usr/bin/perl
use strict; # https://perlmonks.org/?node_id=11111868
use warnings;
use Time::HiRes qw( time sleep );
my $fudgefactor = 0.01;
while(1)
{
my $nextsecond = int time + 1;
sleep $nextsecond - time - $fudgefactor;
1 while time < $nextsecond;
printf "%.6f\n", time;
}
Outputs:
1579972033.000003
1579972034.000004
1579972035.000004
1579972036.000004
1579972037.000004
1579972038.000005
1579972039.000003
1579972040.000004
1579972041.000004
1579972042.000003
1579972043.000003
1579972044.000004
1579972045.000003
1579972046.000005
1579972047.000003
Looks fairly consistent :)
| [reply] [d/l] [select] |
|
|
use strict;
use warnings;
my $fudgefactor = 0.01;
while (1) {
my $nextsecond = int time + 1;
select(undef, undef, undef, $nextsecond - time - $fudgefactor);
1 while time < $nextsecond;
printf "%.6f\n", time;
}
Output:
1579973997.000000
1579973998.000000
1579973999.000000
1579974000.000000
1579974001.000000
^C
| [reply] [d/l] [select] |
|
|
$ corelist Time::HiRes
Data for 2020-01-20
Time::HiRes was first released with perl v5.7.3
| [reply] [d/l] |
Re: missing second of time
by haukex (Archbishop) on Jan 25, 2020 at 18:19 UTC
|
| [reply] [d/l] |
Re: missing second of time
by roboticus (Chancellor) on Jan 25, 2020 at 11:29 UTC
|
Update: After finishing my coffee, I realize that it's normal behavior: it's just an artifact of adding a number slightly larger than an integer (epsilon_1) to another number slightly less than another integer (epsilon_2), where epsilon_1 happens to be greater than epsilon_2. As an example: 5.99 + 1.02 => 7.01
I gave it a few tries and was able to reproduce it:
$ perl -MTime::HiRes=time -le 'while () { $a=time; print $a, " ", $a-$
+b; $b=$a; sleep 1.01 }'
Use of uninitialized value $b in subtraction (-) at -e line 1.
1579951233.92519 1579951233.92519
1579951234.92536 1.00017690658569
1579951235.92573 1.00036287307739
1579951236.92672 1.00098919868469
1579951237.93894 1.01222395896912
1579951238.95456 1.01561999320984
1579951239.97017 1.01561403274536
1579951240.98579 1.01561689376831
1579951242.00141 1.01561808586121 !!!!
1579951243.01703 1.01561903953552
$ perl -MTime::HiRes=time -le 'print $Time::HiRes::VERSION'
1.9741
$ perl --version
This is perl 5, version 26, subversion 3 (v5.26.3) built for x86_64-cy
+gwin-threads-multi
(with 7 registered patches, see perl -V for more detail)
Copyright 1987-2018, Larry Wall
Perl may be copied only under the terms of either the Artistic License
+ or the
GNU General Public License, which may be found in the Perl 5 source ki
+t.
Complete documentation for Perl, including FAQ lists, should be found
+on
this system using "man perl" or "perldoc perl". If you have access to
+ the
Internet, point your browser at http://www.perl.org/, the Perl Home Pa
+ge.
Also including output of perl -V for interested parties:
...roboticus
When your only tool is a hammer, all problems look like your thumb. | [reply] [d/l] [select] |
Re: missing second of time
by karlgoethebier (Abbot) on Jan 25, 2020 at 16:39 UTC
|
Re: timer in perl
«The Crux of the Biscuit is the Apostrophe»
perl -MCrypt::CBC -E 'say Crypt::CBC->new(-key=>'kgb',-cipher=>"Blowfish")->decrypt_hex($ENV{KARL});'Help
| [reply] [d/l] |
Re: missing second of time
by Anonymous Monk on Jan 25, 2020 at 11:47 UTC
|
Use with hires printf "%.0f\n", time; | [reply] |
|
|
It can still happen sometimes. If you sleep for a time longer than 1s, there is a time interval in which the number of sleeps won't be the same as the number of seconds. A similar problem has been discussed recently in The most precise second (timer).
map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
| [reply] [d/l] |
|
|
You're generously overthinking op is an ijit
only needs rounding
1579941922.99824
1.00389
1579941924.00213 <- WTF!
| [reply] [d/l] |