# Relation of coroutines, threads, and Tasks

**URL:** <https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735>\
**Category:** General Usage\
**Tags:** question, parallel, multithreading, task\
**Created:** [September 24, 2022, 3:00am UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735 "2022-09-24T03:00:47Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ross\_Boylan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ross_boylan/32/9210_2.png) [@Ross\_Boylan](https://discourse.julialang.org/u/Ross_Boylan)\
**Post date:** [September 24, 2022, 3:00am UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735/1 "2022-09-24T03:00:47Z")

</div>

A simple version of my question is “How can `Task`s and `Channel`s, which are coroutine-related, be used safely with threads?”

The “how” here is more in these sense of “how is it possible” than “how do I code it”, since there are already examples of that. Although it is also in the sense “how do I know which patterns are safe”?

The manual’s initial discussion of [parallel computing](https://docs.julialang.org/en/v1/manual/parallel-computing/#Parallel-Computing) describes the first approach as involving `Task`s, coroutines, and `Channel`s. The second approach uses threads. Even this initial discussion mentions threads being used to run `Task`s.

`Channel`s are presented as a way to safely communicate between coroutines. But this [answer](https://discourse.julialang.org/t/pattern-for-managing-thread-local-storage/54023/2) uses a `Channel` to communicate between threads.

I would not assume that a mechanism that provided safe communication among coroutines would provide safe communication between OS threads, which have their own set of locking primitives. And I don’t see anything in the documentation of `Channel` to suggest it is thread-safe.

But the manual clearly indicates that `Task`s and coroutines are intended to go together, and a lot of responses in this forum by people clearly more familiar than I with parallelism in `julia` do mix them. So what’s going on?

In particular, how do I know what forms of mixing are safe and what aren’t?

And how is it that they do mix? For example, architecturally is it that coroutines are used to manage the threads, so that they are really at 2 distinct layers?

My understanding is that coroutines, also known as green threads, are quite distinct from operating system threads. In some ways they are opposites. Green threads involve less overhead than OS threads and so solve the excessive resource demands of the latter. On the other hand, OS threads can preempt each other, while coroutines must explicitly yield control to allow others to run in a process referred to as cooperative multitasking. OS threads can use hardware resources for real parallel execution, while green threads are about letting each other work while they wait for input, i.e., the computer is only handling one at a time. `Core.Task` _is_ a coroutine according to the [manual](https://docs.julialang.org/en/v1/base/parallel/#Tasks).

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 24, 2022, 4:10am UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735/2 "2022-09-24T04:10:59Z")

</div>

If we are just talking solely about Julia and it’s standard library, the only interface you have to threads are `Task`s.

Notice that when you use `Thread.@spawn` you get a `Task`:

```julia
julia> Threads.@spawn sleep(5)
Task (runnable) @0x00007f3fee5beca0

```

If you look under the hood, you will see that all `Theads.@spawn` does is create a `Task` and sets the `sticky` property to false.

```julia
julia> @macroexpand Threads.@spawn sleep(5)
quote
    #= threadingconstructs.jl:181 =#
    let
        #= threadingconstructs.jl:182 =#
        local var"#3#task" = Base.Threads.Task((()->begin
                            #= threadingconstructs.jl:178 =#
                            sleep(5)
                        end))
        #= threadingconstructs.jl:183 =#
        (var"#3#task").sticky = false
        #= threadingconstructs.jl:184 =#
        if $(Expr(:islocal, Symbol("##sync#41")))
            #= threadingconstructs.jl:185 =#
            Base.Threads.put!(var"##sync#41", var"#3#task")
        end
        #= threadingconstructs.jl:187 =#
        Base.Threads.schedule(var"#3#task")
        #= threadingconstructs.jl:188 =#
        var"#3#task"
    end
end

```

The interface to threads in Julia is `Task`-based. Sometimes the `Task` may run on a different thread if you used `Threads.@spawn`.

A `Channel` is used for communicating between `Task`s whether be on the same thread or not. If you look in the documentation of `Channel` you should see a `spawn` keyword:

> If `spawn = true`, the `Task` created for func may be scheduled on another thread in parallel, equivalent to creating a task via `Threads.@spawn`.

---

<div class="post-metadata">

**Author:** ![Ross\_Boylan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ross_boylan/32/9210_2.png) [@Ross\_Boylan](https://discourse.julialang.org/u/Ross_Boylan)\
**Post date:** [September 30, 2022, 8:03pm UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735/3 "2022-09-30T20:03:20Z")

</div>

> [@mkitti](#):
>
> If we are just talking solely about Julia and it’s standard library, the only interface you have to threads are `Task`s.

What about `Thread.@threads`? Do you mean that too uses `Task`s underneath? `@threads` and `@threadcall` (“may be removed/changed in future versions of Julia”) are the only ones described in [Multi-Threading · The Julia Language](https://docs.julialang.org/en/v1/manual/multi-threading/#man-multithreading), though it has a couple of cryptic mentions of `@spawn`.

Thanks to your pointer to `@spawn` I got something going using threads and tasks. The `@threads` didn’t fit because I had per-thread setup I needed to do.

So I guess `Task` is a coroutine that may sometimes be executed off the main thread.

This means that one of the usual advantages of coroutines, that one can often avoid locking because when and where control is yielded can be controlled, actually does not apply to `Julia` coroutines when they are running on multiple threads, right?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [September 30, 2022, 9:35pm UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735/4 "2022-09-30T21:35:25Z")

</div>

`@threadcall` for calling external libraries. If that is not what you are doing, I would not use that.

Here is the documentation for `Threads.@spawn`:

[https://docs.julialang.org/en/v1/base/multi-threading/#Base.Threads.@spawn](https://docs.julialang.org/en/v1/base/multi-threading/#Base.Threads.@spawn)

Whether a `Task` executes on the current thread or a different thread, it will not block execution on current thread unless you wait for it. `@threads for` is a construct to simplify launching multiple `Tasks` on different threads and then it waits for all of them to complete.

---

<div class="post-metadata">

**Author:** ![Ross\_Boylan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ross_boylan/32/9210_2.png) [@Ross\_Boylan](https://discourse.julialang.org/u/Ross_Boylan)\
**Post date:** [October 1, 2022, 7:35am UTC](https://discourse.julialang.org/t/relation-of-coroutines-threads-and-tasks/87735/5 "2022-10-01T07:35:04Z")

</div>

> [@mkitti](#):
>
> Here is the documentation for `Threads.@spawn`:

Yes, I’m aware. The point I was trying to make is that the introductory discussion of threads provides almost nothing about `@spawn` (despite 2 references to `@spawn` that presume we already know what it is), and it seems to me it should. Instead it’s all about `@threads` and `@threadcall`. You are correct: `@threadcall` is not for my current case.
