`waitall(tasks)` doesn't throw as `foreach(wait, tasks)` does

I have a tasks which is a vector of Tasks.

If I use foreach(wait, tasks), then it will throw like this (which is expected behavior)

julia> fill_model_D_X!(inn, X)
 rest = 1, j = 40304412
Warning: 1.760797410756771e9 terminate all solves
ERROR: TaskFailedException
Stacktrace:
 [1] #wait#582
   @ ./task.jl:363 [inlined]
 [2] wait
   @ ./task.jl:360 [inlined]
 [3] foreach
   @ ./abstractarray.jl:3188 [inlined]
 [4] fill_model_D_X!(v::Vector{JuMP.Model}, X::Vector{NamedTuple})
   @ Main ./REPL[40]:38
 [5] top-level scope
   @ REPL[59]:1

    nested task error: UNKNOWN_RESULT_STATUSINTERRUPTED
    Stacktrace:
     [1] error(s::String)
       @ Base ./error.jl:44
     [2] get_a_paired_block(O::Vector{Int64})
       @ Main ./REPL[25]:53
     [3] (::var"#fill_model_D_X!##0#fill_model_D_X!##1"{Vector{…}, Vector{…}, Base.Threads.Atomic{…}})(j::Int64)
       @ Main ./REPL[40]:5
     [4] (::var"#fill_model_D_X!##4#fill_model_D_X!##5"{Int64, var"#fill_model_D_X!##0#fill_model_D_X!##1"{…}})()
       @ Main ./REPL[40]:14

However, If I just replace it with waitall(tasks), then the ERROR is not seen (which should exists).

julia> fill_model_D_X!(inn, X) # No ERROR here
 rest = 1, j = 50990457
Warning: 1.760797120923299e9 terminate all solves 

julia> for i = X # But it is indeed problematic, if I check it manually
       end
ERROR: UndefRefError: access to undefined reference

I want to ask: is this normal? Why?

And, what’s the advantage of using waitall in favor of the old alternatives?

3 Likes

It should work with throw=true, but it doesn’t.


julia> t1 = Threads.@spawn (sleep(2); 1 ÷ 1)
Task (runnable, started) @0x00007426bcca6b30

julia> t2 = Threads.@spawn (sleep(2); 1 ÷ 0)
Task (runnable, started) @0x00007426bcca6d10

julia> waitall([t1,t2], throw=true)
(Task[Task (done) @0x00007426bcca6b30, Task (failed) @0x00007426bcca6d10], Task[])

julia> fetch(t1)
1

julia> fetch(t2)
ERROR: TaskFailedException

You should enter an issue at github.

3 Likes

It’s here.

2 Likes

This bug is addressed in the following PR:

And, what’s the advantage of using waitall in favor of the old alternatives?

waitall supports the failfast and throw options. foreach(wait, tasks) is equivalent to waitall(tasks), which is the same as waitall(tasks; failfast=true, throw=true). You can wait for all tasks to complete, even if some tasks throw exceptions, by setting failfast=false. Alternatively, you can handle failed tasks the same way as successful ones by setting throw=false.

2 Likes

Well, to be honest I doubt if they are meaningful in practice. Because exceptions are severe to be eradicated for me. And throwing helps people debug.

1 Like