How to wait for just the first task to complete

Viewed 130

If there are a set of concurrent tasks scheduled, how to wait for the first task to complete?.

Does exists something like wait([t1, t2], return_when=:FIRST_COMPLETED)?

function task1()
    rt = rand()
    @info "task1 time: $rt"
    sleep(rt)
    @info "task 1 done"
end

function task2()
    rt = rand()
    @info "task2 time: $rt"
    sleep(rt)
    @info "task 2 done"
end

t1 = @async task1()
t2 = @async task2()

# wait for just the first completed task
# ??? 
2 Answers

I think something like this would work:

julia> function waitfirst(ts)
           c = Channel{Int}()
           for (i, t) in enumerate(ts)
               @async begin
                   wait(t)
                   put!(c, i)
               end
           end
           r = take!(c)
           @info "Task $r won"
       end
waitfirst (generic function with 1 method)

julia> waitfirst([@async(task1()), @async(task2())])
[ Info: task1 time: 0.6723665203367726
[ Info: task2 time: 0.4815093245244271
[ Info: task 2 done
[ Info: Task 2 won

julia> [ Info: task 1 done
julia> 

julia> waitfirst([@async(task1()), @async(task2())])
[ Info: task1 time: 0.3452659680724035
[ Info: task2 time: 0.8576370382519976
[ Info: task 1 done
[ Info: Task 1 won

julia> [ Info: task 2 done
julia> 

You have to make sure the inputs are scheduled first, though, otherwise it deadlocks.

Similar to channel, you can also use Conditions like this:

c = Condition()
t1 = @async (task1(); notify(c))
t2 = @async (task2(); notify(c))
wait(c)
@info "wake"

Note this only schedule the main task, not directly switch to it. i.e. it is possible that when t1 finished, the main task is waken, but t2 get scheduled first and do some computation heavy work (blocking) before the main task actually continue. You can take a look at yield if you want to make sure the main task runs first.

Related