What is the difference between Threads.@spawn and Threads.@threads?

Viewed 1808

I am a novice programmer interested in the Julia language. The documentation (https://docs.julialang.org/en/v1/base/multi-threading/) says Threads.@threads is for "for" loops and theads.@spawn places a given task on any available thread. My understand is that Threads.@threads is inherently synchronized while the threads.@spawn method is asynchronous and needs more planning to implement (namely using the fetch() method).

In code I find online using both, I seem to see the two used interchangeably (from my perspective). What is the conceptual difference between the two for a novice programmer and how/when should we implement each? Additionally, can they complement each other?

1 Answers

Consider:

function withthreads()
    arr = zeros(Int, 10)
    Threads.@threads for i in 1:10
       sleep(3 * rand())
       arr[i] = i
    end
    println("with @threads: $arr")
end


function withspawn()
    arr = zeros(Int, 10)
    for i in 1:10
        Threads.@spawn begin
            sleep(3 * rand())
            arr[i] = i
        end
    end
    println("with @spawn: $arr")
end

function withsync()
    arr = zeros(Int, 10)
    @sync begin
        for i in 1:10
           Threads.@spawn begin
               sleep(3 * rand())
               arr[i] = i
           end
        end
    end
    println("with @sync: $arr")
end

withthreads()
withspawn()
withsync()

output:

with @threads: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
with @spawn: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
with @sync: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

So @threads manages the pool of threads allotted to julia, and spawns up to one thread for each iteration of the for loop (possibly using the same threads more than once for more than one iteration, sequentially as each thread finishes its allotted iteration, if there are more iterations than threads), and also synchonizes the threads, not exiting the for block until all threads have completed. @spawn spawns just one task thread and returns to the main task immediately, and so the block can be exited as soon as all tasks are spawned, even before they are done working (so the zeros remain 0 in array arr).

Related