在 Julia 中设置算法的时间限制

Set a time limitation on algorithm in Julia

我有一个 Julia 代码,运行 有一段时间了。我想 运行 代码 3 小时,然后终止它。有谁知道最有效的方法是什么。将不胜感激任何建议。谢谢

@async 和@sync 对于 Julia 中的协程类型流程控制非常有用。您可以启动一个异步进程,稍后调用 exit 以终止整个程序:

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)

我建议使用 Distributed 将您的函数生成为一个新进程并控制它的时间(我相信我一直在回答类似的问题,但我找不到答案)。

代码如下:

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

你可以这样使用(请注意外部包是如何导入的):

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

现在让我们运行吧。请注意,第二个返回值是 运行 计算的 workerid(您可能想删除它):

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)

如果我们只给代码 1 秒来执行它将失败:

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

最后,由于发生超时,进程应该被杀死(否则它会继续执行):

rmprocs(wid)

这是一个使用线程的解决方案。我只是乞求在 Julia 中编码,所以它不是高质量的代码,但它可以工作。您首先需要使用 @task 宏将函数包装为任务,然后调用 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

此代码最糟糕的部分是使用 sleep(0.1) 主动等待。我想我可以通过再生成一个线程来摆脱它,所以总共有 3 个:一个执行 origtask 的实际工作,完成后通知一个条件,一个等待提到的条件,另一个将休眠超时秒数,然后通知条件。