# Task scheduling semantics

**URL:** <https://discourse.julialang.org/t/task-scheduling-semantics/62950>\
**Category:** Internals & Design\
**Created:** [June 15, 2021, 2:34pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950 "2021-06-15T14:34:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Christian\_Rorvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christian_rorvik/32/965_2.png) [@Christian\_Rorvik](https://discourse.julialang.org/u/Christian_Rorvik)\
**Post date:** [June 15, 2021, 2:34pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/1 "2021-06-15T14:34:40Z")

</div>

Reading through [https://github.com/JuliaLang/julia/pull/40715](https://github.com/JuliaLang/julia/pull/40715) I believe task migration across threads is primed for 1.7 release. Very much looking forward to this, but also have some concerns around the clarity in semantics of task scheduling.

`@async` launches a task that schedules on and sticks to the current thread. How will this look after the task migration change?

In my view there are two kinds of async-non-concurrent execution you want in the system. For interfacing with external libraries or directly with thread local store, you may need tasks that stick to the current thread. For application layer async code (e.g., to overlap IO) what you typically want is to guarantee non-simultaneous execution of a set of tasks in a group (e.g., with the parent task and its children), however you aren’t restricted from these migrating across threads. I can see a need for both in my own use cases, so either the API needs to be extended to support this distinction, or task migration needs to be prohibited if a task launches any nested sticky tasks.

I’m curious what the plans are and everyone else’s thoughts. On the same token, perhaps the task scheduling macro API could be simplified and cleaned up; for instance with a single macro taking a scheduling policy argument, rather than a macro per use case. Scheduling policies I can think of would be unrestricted, bind-to-current-thread, bind-to-launch-thread, bind-to-parent-thread.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [August 8, 2021, 3:34am UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/2 "2021-08-08T03:34:14Z")

</div>

I needed to know about the new behavior but was also confused about where to look. To link up some information I found:

The co-scheduling behavior of `@async` tasks with their parent tasks was discussed in

[https://github.com/JuliaLang/julia/issues/41324](https://github.com/JuliaLang/julia/issues/41324)

For 1.7, it was decided that unsticky tasks become sticky if they launch any children with `@async`, thus ensuring that `@async` tasks always run on the same thread as their parent.

[https://github.com/JuliaLang/julia/pull/41334](https://github.com/JuliaLang/julia/pull/41334)

This probably isn’t a long term solution, it’s more of a workaround to ensure existing code doesn’t break.

---

<div class="post-metadata">

**Author:** ![Christian\_Rorvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christian_rorvik/32/965_2.png) [@Christian\_Rorvik](https://discourse.julialang.org/u/Christian_Rorvik)\
**Post date:** [August 11, 2021, 3:55pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/3 "2021-08-11T15:55:37Z")

</div>

Thanks 🙂 Yes that first issue is one I posted, and the second spawned out of that discussion. Longer term a stronger API for more advanced control would be great.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [August 11, 2021, 10:53pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/4 "2021-08-11T22:53:29Z")

</div>

Yes, thanks for pushing on that. A fair amount of concurrent code would have been broken without the coscheduling workaround.

---

<div class="post-metadata">

**Author:** ![Taaitaaiger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taaitaaiger/32/49792_2.png) [@Taaitaaiger](https://discourse.julialang.org/u/Taaitaaiger)\
**Post date:** [August 12, 2021, 3:21pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/5 "2021-08-12T15:21:09Z")

</div>

What happens when the root task is yielded? Can a task created with `Base.Threads.@spawn` be rescheduled on the main thread in this case, or can the main thread only run tasks created with `@async` from some task already running on the main thread?

---

<div class="post-metadata">

**Author:** ![Christian\_Rorvik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/christian_rorvik/32/965_2.png) [@Christian\_Rorvik](https://discourse.julialang.org/u/Christian_Rorvik)\
**Post date:** [August 12, 2021, 3:31pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/6 "2021-08-12T15:31:38Z")

</div>

The main thread can pick up tasks like any other. [ThreadPools.jl](https://github.com/tro3/ThreadPools.jl) has some utilities to schedule away from the main thread.

---

<div class="post-metadata">

**Author:** ![Taaitaaiger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taaitaaiger/32/49792_2.png) [@Taaitaaiger](https://discourse.julialang.org/u/Taaitaaiger)\
**Post date:** [August 12, 2021, 3:58pm UTC](https://discourse.julialang.org/t/task-scheduling-semantics/62950/7 "2021-08-12T15:58:08Z")

</div>

Thanks for the information and the tip. It’s a rather painful situation for my planned use-case (I want to wait on an `AsyncCondition` that is notified from Rust with `uv_async_send` whenever Rust needs to reclaim control of the main thread so spamming `jl_process_events` can be avoided and other tasks scheduled on the main thread can be executed), but such is life 🙂
