How to periodically execute coroutines in asyncio when then are potentially longer than the period interval - python-asyncio

I want to execute functions at specific time intervals. Based on this answer, I am able to do so using asyncio, but only when the time the functions take is less than the interval. For example, when the function time (wait) is less than interval time:
wait = 2
interval = 4
async def function1(wait):
await aio.sleep(wait)
t = round(time.time() - start_time, 1)
print("time function1 executed:", t)
async def function2():
t = round(time.time() - start_time, 1)
print("time function2 executed:", t)
async def scheduler(interval):
while True:
t = round(time.time() - start_time, 1)
print("time functions were scheduled:", t)
await aio.gather(
aio.sleep(interval - (time.time() - start_time) % interval),
function1(wait),
function2()
)
start_time = time.time()
aio.run(scheduler(interval))
I get expected behaviour where functions run at my specified interval (4sec):
time functions were scheduled: 0.0
time function2 executed: 0.0
time function1 executed: 2.0
time functions were scheduled: 4.0
time function2 executed: 4.0
time function1 executed: 6.0
time functions were scheduled: 8.0
time function2 executed: 8.0
time function1 executed: 10.0
time functions were scheduled: 12.0
time function2 executed: 12.0
time function1 executed: 14.0
But when wait > interval:
wait = 5
interval = 4
I get:
time functions were scheduled: 0.0
time function2 executed: 0.0
time function1 executed: 5.0
time functions were scheduled: 5.0
time function2 executed: 5.0
time function1 executed: 10.0
time functions were scheduled: 10.0
time function2 executed: 10.0
time function1 executed: 15.0
time functions were scheduled: 15.0
time function2 executed: 15.0
time function1 executed: 20.1
I am completely new to asyncio and have tried playing around with asyncio.wait_for() (using only a single coroutine function) and asyncio.wait() (for multiple coroutine functions) but I keep getting strange behaviours where the scheduling seems to work, but every so often a load of output from the functions is dumped out... I think it may have something to do with cancelling the over-running functions but I don't understand how to cancel them when the interval is up.
Any help would be greatly appreciated.

Related

How to automatically check time?

Is it possible to automatically check time then execute certain codes?
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer == "18:04:40" then
print("hello")
end
I am trying to print hello on "18:04:40" everyday (os.date's time) without setting up a timer (which counts how much time past since the program's initiation) as I can't run the program 24 hours non-stop...
Thanks for reading.
This may not be the best solution but, when using a library like love2d for example you could run something like this:
function love.update(dt)
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer >= value then
--stuff here
end
end
Or if you wanna make it so you have a whole number something like
tick = 0
function love.update(dt)
tick = tick + dt
if tick > 1 then
timer = os.date('%H:%M:%S', os.time() - 13 * 60 * 60 )
if timer >= value then
--stuff here
end
end
end
Lua has to check the time in some way.
Without a loop that can be realized with debug.sethook().
Example with Lua 5.1 typed in an interactive Lua (lua -i)...
> print(_VERSION)
Lua 5.1
> debug.sethook() -- This clears a defined hook
> -- Next set up a hook function that fires on 'line' events
> debug.sethook(function() local hour, min, sec = 23, 59, 59 print(os.date('%H:%M:%S', os.time({year = 2021, month = 12, day = 11, hour = hour, min = min, sec = sec}))) end, 'l')
-- just hit return/enter or do other things
23:59:59
5.9 - The Debug Library
https://www.lua.org/manual/5.1/manual.html#5.9

Ruby time subtraction

There is the following task: I need to get minutes between one time and another one: for example, between "8:15" and "7:45". I have the following code:
(Time.parse("8:15") - Time.parse("7:45")).minute
But I get result as "108000.0 seconds".
How can I fix it?
The result you get back is a float of the number of seconds not a Time object. So to get the number of minutes and seconds between the two times:
require 'time'
t1 = Time.parse("8:15")
t2 = Time.parse("7:45")
total_seconds = (t1 - t2) # => 1800.0
minutes = (total_seconds / 60).floor # => 30
seconds = total_seconds.to_i % 60 # => 0
puts "difference is #{minutes} minute(s) and #{seconds} second(s)"
Using floor and modulus (%) allows you to split up the minutes and seconds so it's more human readable, rather than having '6.57 minutes'
You can avoid weird time parsing gotchas (Daylight Saving, running the code around midnight) by simply doing some math on the hours and minutes instead of parsing them into Time objects. Something along these lines (I'd verify the math with tests):
one = "8:15"
two = "7:45"
h1, m1 = one.split(":").map(&:to_i)
h2, m2 = two.split(":").map(&:to_i)
puts (h1 - h2) * 60 + m1 - m2
If you do want to take Daylight Saving into account (e.g. you sometimes want an extra hour added or subtracted depending on today's date) then you will need to involve Time, of course.
Time subtraction returns the value in seconds. So divide by 60 to get the answer in minutes:
=> (Time.parse("8:15") - Time.parse("7:45")) / 60
#> 30.0

Ruby subtracting two times giving incorrect answer

I am trying to time how long a method takes to execute, so I record the start time and then at the end subtract it from the current time which should give me the difference in seconds. I get back 123 seconds when it actually took over 10 minutes to run.
def perform_cluster_analysis
start = Time.now
# A whole lot of tasks performed here
puts 'time taken: '
puts (Time.now - start)
end
The output I get is:
time taken:
123.395808311
But when timed with a stopwatch it actually took over 10 minutes, so why am I getting back 123 seconds instead of +- 600 (10 minutes)

Matlab structure dismal performance when used with objects

Here is a simple class with two properties: PStruct is a property that will contain a structure.
classdef anobj < handle
properties
PStruct
PNum=1;
end
methods
function obj = anobj()
end
end
end
Here is a script filling the structure in an object with 1’s (pretty fast):
clear all
a = anobj(); % an object
b = anobj(); % another object for future use
ntrials=10; niterations=1000;
a.PStruct(ntrials,niterations).field1=0; % 'initialize' the struct array
for t=1:ntrials
tic;
for i=1:niterations
a.PStruct(t,i).field1=1; % store data
end
toc;
end
yielding:
Elapsed time is 0.001008 seconds.
Elapsed time is 0.000967 seconds.
Elapsed time is 0.000972 seconds.
Elapsed time is 0.001206 seconds.
Elapsed time is 0.000992 seconds.
Elapsed time is 0.000981 seconds.
Elapsed time is 0.000975 seconds.
Elapsed time is 0.001072 seconds.
Elapsed time is 0.000951 seconds.
Elapsed time is 0.000994 seconds.
When instead I use a property of another object (=1 as well), changing the line within the loops to:
a.PStruct(t,i).field1=b.PNum; % store data
I get:
Elapsed time is 0.112418 seconds.
Elapsed time is 0.107359 seconds.
Elapsed time is 0.118347 seconds.
Elapsed time is 0.127111 seconds.
Elapsed time is 0.138606 seconds.
Elapsed time is 0.152675 seconds.
Elapsed time is 0.162610 seconds.
Elapsed time is 0.172921 seconds.
Elapsed time is 0.184254 seconds.
Elapsed time is 0.190802 seconds.
Not only performance is orders of magnitude slower, but also there is a very clear trend (verified more generally) of slowing down with each trial. I don’t get it. Furthermore, if I instead use a standalone uninitialized struct array which is not an object property (this line replaces the one within the loops):
PStruct(t,i).field1=b.PNum; % store data
I get ok performance with no trends:
Elapsed time is 0.007143 seconds.
Elapsed time is 0.004208 seconds.
Elapsed time is 0.004312 seconds.
Elapsed time is 0.004382 seconds.
Elapsed time is 0.004302 seconds.
Elapsed time is 0.004545 seconds.
Elapsed time is 0.004499 seconds.
Elapsed time is 0.005840 seconds.
Elapsed time is 0.004210 seconds.
Elapsed time is 0.004177 seconds.
There is some weird interaction between struct arrays and objects. Does anybody know what is happening and how to fix this? Thanks.
Very strange.
I found that if you do either of the following the code returns to normal speed
c = b.PNum;
a.PStruct(t,i).field1=c; % store data
or
a.PStruct(t,i).field1=int32(b.PNum); % store data
but if you use double the code is still slow
a.PStruct(t,i).field1=double(b.PNum); % store data
and if you use both 'fast' methods at the same time
c = b.PNum;
a.PStruct(t,i).field1=c; % store data
a.PStruct(t,i).field1=int32(b.PNum); % store data
the slow speed returns.

how to judge of the trade-off of lua closure and lua coroutine?(when both of them can perform the same task)

ps:let alone the code complexity of closure implementation of the same task.
The memory overhead for a closure will be less than for a coroutine (unless you've got a lot of "upvalues" in the closure, and none in the coroutine). Also the time overhead for invoking the closure is negligible, whereas there is some small overhead for invoking the coroutine. From what I've seen, Lua does a pretty good job with coroutine switches, but if performance matters and you have the option not to use a coroutine, you should explore that option.
If you want to do benchmarks yourself, for this or anything else in Lua:
You use collectgarbage("collect");collectgarbage("count") to report the size of all non-garbage-collectable memory. (You may want to do "collect" a few times, not just one.) Do that before and after creating something (a closure, a coroutine) to know how much size it consumes.
You use os.clock() to time things.
See also Programming in Lua on profiling.
see also:
https://gist.github.com/LiXizhi/911069b7e7f98db76d295dc7d1c5e34a
-- Testing coroutine overhead in LuaJIT 2.1 with NPL runtime
--[[
Starting function test...
memory(KB): 0.35546875
Functions: 500000
Elapsed time: 0 s
Starting coroutine test...
memory(KB): 13781.81640625
Coroutines: 500000
Elapsed time: 0.191 s
Starting single coroutine test...
memory(KB): 0.4453125
Coroutines: 500000
Elapsed time: 0.02800000000002
conclusions:
1. memory overhead: 0.26KB per coroutine
2. yield/resume pair overhead: 0.0004 ms
if you have 1000 objects each is calling yield/resume at 60FPS, then the time overhead is 0.2*1000/500000*60*1000 = 24ms
and if you do not reuse coroutine, then memory overhead is 1000*60*0.26 = 15.6MB/sec
]]
local total = 500000
local start, stop
function loopy(n)
n = n + 1
return n
end
print "Starting function test..."
collectgarbage("collect");collectgarbage("collect");collectgarbage("collect");
local beforeCount =collectgarbage("count")
start = os.clock()
for i = 1, total do
loopy(i)
end
stop = os.clock()
print("memory(KB):", collectgarbage("count") - beforeCount)
print("Functions:", total)
print("Elapsed time:", stop-start, " s")
print "Starting coroutine test..."
collectgarbage("collect");collectgarbage("collect");collectgarbage("collect");
local beforeCount =collectgarbage("count")
start = os.clock()
for i = 1, total do
co = coroutine.create(loopy)
coroutine.resume(co, i)
end
stop = os.clock()
print("memory(KB):", collectgarbage("count") - beforeCount)
print("Coroutines:", total)
print("Elapsed time:", stop-start, " s")
print "Starting single coroutine test..."
collectgarbage("collect");collectgarbage("collect");collectgarbage("collect");
local beforeCount =collectgarbage("count")
start = os.clock()
co = coroutine.create(function()
for i = 1, total do
loopy(i)
coroutine.yield();
end
end)
for i = 1, total do
coroutine.resume(co, i)
end
stop = os.clock()
print("memory(KB):", collectgarbage("count") - beforeCount)
print("Coroutines:", total)
print("Elapsed time:", stop-start, " s")

Resources