MiniQuark
MiniQuark

Reputation: 48446

How to run computations for n seconds in Julia?

I'd like to run heavy computations in Julia for a fixed duration, for example 10 seconds. I tried this:

timer = Timer(10.0)
while isopen(timer)
    computation()
end

But this does not work, since the computations never let Julia's task scheduler take control. So I added yield() in the loop:

timer = Timer(10.0)
while isopen(timer)
    yield()
    computation()
end

But now there is significant overhead from calling yield(), especially when one call to computation() is short. I guess I could call yield() and isopen() only every 1000 iterations or so, but I would prefer a solution where I would not have to tweak the number of iterations every time I change the computations. Any ideas?

Upvotes: 1

Views: 279

Answers (1)

Przemyslaw Szufel
Przemyslaw Szufel

Reputation: 42214

This pattern below uses threads and on my laptop has a latency of around 35ms for each 1,000,000 calls which is more than acceptable for any job.

Tested on Julia 1.5 release candidate:

function should_stop(timeout=10)
    handle = Threads.Atomic{Bool}(false)
    mytask = Threads.@spawn begin
        sleep(timeout)
        Threads.atomic_or!(handle, true)
    end
    handle
end


function do_some_job_with_timeout()
    handle = should_stop(5)
    res = BigInt() # save results to some object
    mytask = Threads.@spawn begin
        for i in 1:10_000_000
            #TODO some complex computations here
            res += 1 # mutate the result object
            handle.value && break
        end
    end
    wait(mytask) # wait for the job to complete
    res
end

You can also used Distributed instead. The code below seems to have a much better latency - only about 1ms for each 1,000,000 timeout checks.

using Distributed
using SharedArrays
addprocs(1)
function get_termination_handle(timeout=5,workerid::Int=workers()[end])::SharedArray{Bool}
    handle = SharedArray{Bool}([false])
    proc = @spawnat workerid begin
        sleep(timeout)
        handle[1]=true
    end
    handle
end


function fun_within_timeout()
    res = 0
    h = get_termination_handle(0.1)
    for i = 1:100_000_000
        res += i % 2 == 0 ? 1 : 0
        h[1] && break
    end
    res
end

Upvotes: 1

Related Questions