1

I have a Julia code which runs for quite sometime. I want to run the code for 3 hours and then terminate it. Does anyone know what is the most efficient way to do this. Would appreciate any advice. Thanks

2
  • Easiest way would be using the OS, are you on Linux, using Bash? Timeout is bundled in coreutils, which you can install from brew, if you're on a mac. gnu.org/software/coreutils/manual/html_node/… Commented Oct 27, 2018 at 15:22
  • Can your code check a timer, or do you just want to run it without any interruptions and then get killed when time's up? Commented Oct 27, 2018 at 17:52

3 Answers 3

4

@async and @sync are really useful for coroutine type process control in Julia. You can start an async process that calls exit at a later point so as to terminate the entire program:

function killafterseconds(s)
    @async begin 
        sleep(s)
        println("terminating after $s seconds")
        exit(0)
    end
end

function countdown(n)
    for t in n:-1:0
        println(t)
        sleep(1)
    end
end

killafterseconds(10)

countdown(10000)
Sign up to request clarification or add additional context in comments.

Comments

2

Here's a solution using threads. I'm just begginging coding in Julia so it's not high quality code, but it works. You first need to wrap your function as a Task, by using the @task macro, and then call runTask():

    function runTask(origtask:: Task, timeoutms:: Int)
        startTime = Dates.datetime2epochms(now())

        function internal_task(taskFinished)
            try
                schedule(origtask)
                yield()
                wait(origtask)
                if istaskdone(origtask)
                    taskFinished[] = true
                    Base.task_result(origtask)
                else
                    throw(ErrorException("Task is not done even after wait() for it to finish - something is wrong"))
                end
            catch e
                @warn "Error while processing task: $e"
                taskFinished[] = true
                missing
            end
        end

        taskFinished = Threads.Atomic{Bool}(false)
        thread = Threads.@spawn internal_task(taskFinished)
        while !taskFinished[] && (Dates.datetime2epochms(now()) - startTime) < timeoutms
            sleep(0.1)
        end
        if taskFinished[]
            return fetch(thread)
        end
        # Task timeouted
        origtask.exception = InterruptException()
        return missing
    end # function

The worst part of this code is active waiting using sleep(0.1). I guess I could get rid of it by spawning one more thread, so there would be 3 in total: one would execute the actual work from the origtask and after doing it would notify a condition, one would wait on the mentioned condition and another one would sleep for the timeout number of seconds and then notify the condition.

Comments

1

I recommend using Distributed to spawn your function as a new process and control it's time (I believe I have been answering similar question but I cannot find the answer).

Here is the code:

using Distributed
function run_with_timeout(timeout::Int,f::Function, wid::Int)
    result = RemoteChannel(()->Channel{Tuple}(1));
    @spawnat wid put!(result, (f(),myid()))
    res = (:timeout, wid)
    time_elapsed = 0.0
    while time_elapsed < timeout && !isready(result)
        sleep(0.5)
        time_elapsed += 0.5
    end
    if !isready(result)
        println("Timeout! at $wid")
    else
        res = take!(result)
    end
    return res
end

You can use it like this (please note how external packages are imported):

wid = addprocs(1)[1]
@everywhere using DataFrames
@everywhere function ff()
    sleep(2)
    #code fir making heavy computations
    #this is the place to write whatever you need
    return DataFrame(x=[1,2],y=[1,3])
end

Now let us run it. Note that the second returned value is the workerid to run computations (you might want to remove it):

julia> run_with_timeout(10,() ->(try;ff();catch ee;dump(ee);end ),wid)
(2×2 DataFrame
│ Row │ x     │ y     │
│     │ Int64 │ Int64 │
├─────┼───────┼───────┤
│ 1   │ 1     │ 1     │
│ 2   │ 2     │ 3     │, 2)

If we give our code only 1 sec to execute it will fail:

julia> run_with_timeout(1,() ->(try;ff();catch ee;dump(ee);end ),wid)
Timeout! at 2
(:timeout, 2)

Finally, since the timeout occured the process should be killed (otherwise it would continue to execute):

rmprocs(wid)

2 Comments

I think it works but I am not quite sure which goes where! (I'm somewhat a beginner, so apologies for the silly questions). I'm just wondering why do you need the second sleep in the function arguments? and where should I put this command? inside my while loop (the one I want to terminate) or should this be outside & I should put my code into a function & put it somewhere in your function. if so, where exactly should it goes? I tried playing around with you had and I can tell that the first argument is for how many seconds I wanted it to last but I not sure about the rest! Thanks in advance.
I updated the code to be more readable and useful. You need to place your code in the ff() function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.