# Difference b/w @threads and @spawn macros

**URL:** <https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984>\
**Category:** General Usage\
**Tags:** question, parallel\
**Created:** [January 15, 2023, 6:31am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984 "2023-01-15T06:31:24Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![sajjad\_khan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sajjad_khan/32/45202_2.png) [@sajjad\_khan](https://discourse.julialang.org/u/sajjad_khan)\
**Post date:** [January 15, 2023, 6:31am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984/1 "2023-01-15T06:31:24Z")

</div>

What the difference b/w @threads and @spawn? It’s mentioned somewhere that @spawn spawns just one task thread. If so then how it can be different than @threads?

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [January 15, 2023, 7:29am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984/2 "2023-01-15T07:29:58Z")

</div>

Have you read the manual and the docstrings of the macros? If so, what’s unclear?

You might also take a look at this: [JuliaHLRS22/4\_multithreading.ipynb at main · carstenbauer/JuliaHLRS22 · GitHub](https://github.com/carstenbauer/JuliaHLRS22/blob/main/Day3/4_multithreading.ipynb)

---

<div class="post-metadata">

**Author:** ![sajjad\_khan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sajjad_khan/32/45202_2.png) [@sajjad\_khan](https://discourse.julialang.org/u/sajjad_khan)\
**Post date:** [January 17, 2023, 5:37am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984/3 "2023-01-17T05:37:08Z")

</div>

@carstenbauer How these two are different?

@threads for i in 1:2\*Threads.nthreads()  
println("Hi, I’m ", Threads.threadid())  
end

for i in 1:2\*Threads.nthreads()  
@spawn println("Hi, I’m ", Threads.threadid())  
end

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [January 17, 2023, 7:27am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984/4 "2023-01-17T07:27:05Z")

</div>

One difference:

```julia
begin 
    Threads.@threads for i in 1:2*Threads.nthreads()
        println("Hi, I’m ", Threads.threadid())
    end
        
    println("after loop")
end

```

returns

```julia
Hi, I’m 3
Hi, I’m 2
Hi, I’m 1
Hi, I’m 1
Hi, I’m 2
Hi, I’m 2
Hi, I’m 4
Hi, I’m 4
Hi, I’m 3
Hi, I’m 3
after loop

```

whereas

```julia
begin 
    
    for i in 1:2*Threads.nthreads()
        Threads.@spawn println("Hi, I’m ", Threads.threadid())
    end
    println("after loop")
end

```

returns the following, in this order:

```julia
after loop
Hi, I’m 1
Hi, I’m 3
Hi, I’m 3
Hi, I’m 2
Hi, I’m 3
Hi, I’m 2
Hi, I’m 4
Hi, I’m 2

```

As you see, the code with `@spawn` first printed `after loop`, (at least this time).  
So why is that? To put it short, `@spawn` off-loads whatever task comes after it (so here the printing direction) to a newly spawned thread on whatever core is available right now and then **immediately moves on**.  
So in this case, every time the loop hits `@spawn`, it tells one of the cores to go and print something and then while these cores are doing their thing it moves on and prints `after loop`.

`@threads` is much more restrictive, essentially you always place it in front of a loop and then it schedules a bunch of tasks and assigns them to the cores (In newer Julia versions this scheduling can also be dynamic as in the previous case). More importantly, it only parallelizes over a loop and waits until every element of the loop is properly finished before it allows the main process to continue.

`@spawn` allows for a bit more fine-tuning. You can spawn threads outside a loop, or within a nested loop:

```julia
begin
    Threads.@spawn println(1)
    Threads.@spawn println(2)
end
# 2
# 1

Threads.@sync begin
    for i in 1:3
        for j in 1:2
            Threads.@spawn println((i,j))
        end
    end
end
#(1, 1)
#(2, 2)
#(3, 2)
#(3, 1)
#(2, 1)

```

By the way the `@sync` in the last example is to syncronize all the task, i.e. to wait for all processes to finish before returning (In this case a bit pointless but often something you want to do before returning results).

I think since `@threads` can see “ahead” how many tasks need to be created, it probably has a bit less overhead (?) but I’m not sure to be honest. I think as a rule of thumb, if you have a loop that you want to parallelize over, its best to use `@threads`, if you need to fine-tune a bit more in how exactly the tasks are created, `@spawn` is best.

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [January 17, 2023, 8:28am UTC](https://discourse.julialang.org/t/difference-b-w-threads-and-spawn-macros/92984/5 "2023-01-17T08:28:11Z")

</div>

See what @Salmon said above (`@threads` is “blocking”, `@spawn` is not).

> [@Salmon](#):
>
> I think since `@threads` can see “ahead” how many tasks need to be created, it probably has a bit less overhead (?) but I’m not sure to be honest. I think as a rule of thumb, if you have a loop that you want to parallelize over, its best to use `@threads`, if you need to fine-tune a bit more in how exactly the tasks are created, `@spawn` is best.

Yes, `@threads` looks at the iteration range and, depending on the scheduling scheme, decides how to map this iteration range to a bunch of tasks. For example, based on the number of available Julia threads, `@threads :static` splits up the iteration range evenly, creates precisely one task per thread, and schedules the tasks statically (first thread gets the first task, second the second and so on). `@threads :dynamic` (default) on the other hand creates O(numthreads) many tasks (how many exactly is an implementation detail) and schedules them dynamically (this has a bit of overhead but has the advantage that it allows for composable multithreading for example). The `@spawn` version creates “length of iteration range” many tasks, because it creates one task per iteration and scheduling is dynamic as well. Depending on how many threads there are and how long the iteration range is this will have higher overhead(creation and dynamic scheduling of O(numthreads) vs “length of iteration range” many tasks).

(BTW, this is also (to some extent) explained in the material I linked above)
