# Multithreading @threads inside @spawn

**URL:** <https://discourse.julialang.org/t/multithreading-threads-inside-spawn/60491>\
**Category:** Performance\
**Tags:** multithreading\
**Created:** [May 4, 2021, 1:27am UTC](https://discourse.julialang.org/t/multithreading-threads-inside-spawn/60491 "2021-05-04T01:27:49Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Paul\_McVay](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paul_mcvay/32/4307_2.png) [@Paul\_McVay](https://discourse.julialang.org/u/Paul_McVay)\
**Post date:** [May 4, 2021, 1:27am UTC](https://discourse.julialang.org/t/multithreading-threads-inside-spawn/60491/1 "2021-05-04T01:27:49Z")

</div>

Are threads inside a spawn supposed to find empty threads to use? For example, my function uses `@threads` to perform 3 10 second `sleep`s in 10 seconds total. If I then try to spawn 3 of these function calls, ideally I would want them to happen in parrallel and take 10 seconds. However, it takes 30 seconds to run it. Why do spawn and threads not find the empty threads to run it on? I’ve launched julia with 10 threads on a 20 thread machine.

Working example demonstrating

```julia
function test(str)
    Threads.@threads for i in 1:3
        sleep(10)
    end
    return "$str done"
end 

t1 = Threads.@spawn test("one")
t2 = Threads.@spawn test("two")
t3 = Threads.@spawn test("three")
fetch(t1)
fetch(t2)
fetch(t3)

```

If 9 threads were used for each sleep, it would take 10 seconds total instead of the 30 seconds.

```julia
julia> Threads.nthreads()
10

```

```julia
[pmcvay@pmcvay ~]$ nproc
20

```

---

<div class="post-metadata">

**Author:** ![Paul\_McVay](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paul_mcvay/32/4307_2.png) [@Paul\_McVay](https://discourse.julialang.org/u/Paul_McVay)\
**Post date:** [May 4, 2021, 1:31am UTC](https://discourse.julialang.org/t/multithreading-threads-inside-spawn/60491/2 "2021-05-04T01:31:22Z")

</div>

Ahh. `@threads` inside `spawn` uses only one thread

```julia
t1 = Threads.@spawn test("one")
fetch(t1)

```

This takes 30 seconds.

Any advice on how to accomplish what I am trying to do?

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [May 4, 2021, 2:57am UTC](https://discourse.julialang.org/t/multithreading-threads-inside-spawn/60491/3 "2021-05-04T02:57:46Z")

</div>

`Threads.@threads` does not use dynamic scheduling and so does not perform well when iterating over an array of length around `nthreads()` or less, especially when using calling multiple functions using `@threads` in parallel.

```julia
julia> Threads.nthreads()
10

julia> function threads_sched(nsamples = 1000)
           sched = [[[0], [0], [0]] for _ in 1:nsamples]
           for refs in sched
               Threads.@threads for i in 1:3
                   refs[i][1] = Threads.threadid()
               end
           end
           sched
       end
threads_sched (generic function with 2 methods)

julia> unique(threads_sched())
1-element Vector{Vector{Vector{Int64}}}:
 [[1], [2], [3]]

```

Furthermore, as you observed, there is no parallelism if you start `@threads` in a non-primary thread:

```julia
julia> Threads.@threads for _ in 1:Threads.nthreads()
           if Threads.threadid() == 2
               global sched = threads_sched()
           end
       end

julia> unique(sched)
1-element Vector{Vector{Vector{Int64}}}:
 [[2], [2], [2]]

```

We don’t have this problem in `@spawn`:

```julia
julia> function spawn_sched(nsamples = 1000)
           sched = [[[0], [0], [0]] for _ in 1:nsamples]
           for refs in sched
               @sync for i in 1:3
                   Threads.@spawn refs[i][1] = Threads.threadid()
               end
           end
           sched
       end
spawn_sched (generic function with 2 methods)

julia> unique(spawn_sched())
388-element Vector{Vector{Vector{Int64}}}:
 [[7], [1], [2]]
 [[2], [2], [1]]
 [[2], [7], [7]]
 [[4], [7], [2]]
 ...

```

If you want dynamic scheduling, I recommend avoid using `@threads`. If you want APIs more high level than `@spawn` (which is hard to use), there are high-level API packages such as [FLoops.jl](https://github.com/JuliaFolds/FLoops.jl) and [Folds.jl](https://github.com/JuliaFolds/Folds.jl) that do not have the problem of `@threads`.
