I’m running a loop asynchronously. I’d like to have each iteration take at most max_ns nanoseconds. Here’s what i have so far:
function wait4it(t₀, max_ns)
t₁ = time_ns()
t = t₁ - t₀
if t < max_ns
s = 1e-9*(max_ns - t)
sleep(s)
end
nothing
end
max_ns = 10^9
@async while true
t₀ = time_ns()
sleep(0.1) # and things
wait4it(t₀, max_ns)
end
But I’m wondering if there is anything similar/better out there?
I hope I interpreted your code correctly: I assumed you gave an example of what one iteration would look like, i.e. the body of the while/for loop.
I modified your example in the following way:
max_s = 1
cond = Condition()
for i in 1:5
Timer(_ -> notify(cond), max_s)
sleep(0.1) # and things
wait(cond)
@show i
end
because there is no need to async the stuff that’s done in the loop – I don’t want the loop to continue unless that iteration is done. It worked well, except when the time needed to complete one iteration was longer than max_s, for instance if you replace
sleep(0.1) # and things
with
sleep(2) # and things
it gets stuck on the wait statement and never completes.
function twait(f::Function, timeout::Real=5)
cond = Condition()
Timer(x->notify(cond), timeout)
t = @async begin
res = f()
notify(cond)
res
end
wait(cond)
t.state == :done ? fetch(t) : :timeout
end
If then we have a “heavy” computation, we can do:
heavy(t) = (sleep(t); return t) # a heavy computation taking t seconds
julia> twait(2) do
heavy(1)
end
1
julia> twait(2) do
heavy(3)
end
:timeout
First and foremost, thank you very much @pbayer, I didn’t know about Timer and I learned something new with the @async call to the “heavy” function that allowed the wait to actually work.
I, of course, completely botched the description of what it was I actually needed… I meant to ask for “…each iteration [to] take at mostleastmax_nsmin_ns nanoseconds…”, which lead to my great confusion. But adapting your answer to my needs was simple:
function twait(f, mint)
cond = Condition()
Timer(x->notify(cond), mint)
t = @async $f()
wait(cond)
fetch(t)
end
I don’t have any good reasons to, f being a function and not a variable. But when I @btime:ed this code I got a small residual (instead of 2 s it took 2.002 s) and I was experimenting to see if interpolating f would make a difference… It didn’t.
In the case where f doesn’t have anything to return (side affects are mutating some other variable in place), replacing the fetch(t) with wait(t) doesn’t change the results above either. In any case, that residual is negligent.