# Discussion on ThreadPools.jl

**URL:** <https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283>\
**Category:** Performance\
**Created:** [July 25, 2021, 11:05pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283 "2021-07-25T23:05:40Z")\
**Posts on this page:** 6\
**Page:** 1

<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:** [July 25, 2021, 11:05pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/1 "2021-07-25T23:05:40Z")

</div>

Continuing the discussion from [Multithreaded compute farm](https://discourse.julialang.org/t/multithreaded-compute-farm/65047/21):

> [@Multithreaded compute farm](https://discourse.julialang.org/t/multithreaded-compute-farm/65047/21):
>
> > [@Multithreaded compute farm](https://discourse.julialang.org/t/multithreaded-compute-farm/65047/19):
> >
> > ThreadPools.jl introduces overheads since it tries to disable what Julia runtime does (e.g., task migration across OS threads, in Julia 1.7 and later)
> 
> @tkf could you explain this a little more? I always assumed / hoped that ThreadPools would eventually be made obsolete by Julia’s evolution, but I haven’t seen that happen yet. I’d like to triage what you are saying here to determine if that obsolescence has begun, or if there is some new Julia functionality I need to wrap into the API. Thx

@tro3 I don’t think [the change in Julia 1.7 that allows migration of tasks across threads](https://github.com/JuliaLang/julia/pull/40715) is particularly relevant to ThreadPools. The example overhead I was mentioning was that, since the migration is only allowed for non-sticky tasks, and since ThreadPools need to use sticky tasks by design (to restrict the worker threads to be used by Julia runtime), this new feature is unavailable for code using ThreadPools.

I think the latest discussion that is relevant to ThreadPools is [Severe thread starvation issues · Issue #41586 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/41586#issuecomment-880875258) (though maybe you are already aware of this).

---

<div class="post-metadata">

**Author:** ![tro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tro3/32/12355_2.png) [@tro3](https://discourse.julialang.org/u/tro3)\
**Post date:** [July 26, 2021, 3:22pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/2 "2021-07-26T15:22:53Z")

</div>

Does the “migration” just mean a thread can wake up of any available thread, rather that that first assigned? I agree that is an improvement to Julia, but that would seem to make keeping Tasks off the primary more difficult. I see - hence the sticky bit. Okay, I’ll have to chew on that.

I’ll look at the starvation issue. That one does indeed look interesting.

---

<div class="post-metadata">

**Author:** ![tisztamo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tisztamo/32/16200_2.png) [@tisztamo](https://discourse.julialang.org/u/tisztamo)\
**Post date:** [July 26, 2021, 4:00pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/3 "2021-07-26T16:00:50Z")

</div>

After reading the thread starvation issue [#41586](https://github.com/JuliaLang/julia/issues/41586) carefully I am still unable to understand what is the new info there.

E.g. Wikipedia writes under “[Cooperative multitasking](https://en.wikipedia.org/wiki/Cooperative_multitasking)”:

> As a cooperatively multitasked system relies on each process regularly giving up time to other processes on the system, one poorly designed program can consume all of the CPU time for itself, either by performing extensive calculations or by [busy waiting](https://en.wikipedia.org/wiki/Busy_wait);

It seems to me that this is the case for the described system and the example code. If that is true, then inserting gc safepoints will not be enough, yields are necessary. (But other code may benefit from that, e.g.: [Multi-threadded processing of large number of files faster when reading in batch](https://discourse.julialang.org/t/multi-threadded-processing-of-large-number-of-files-faster-when-reading-in-batch/64968) )

Am I missing something? (To be honest, I do not understand everything, especially in vchuravy’s comment, or what exactly `@threads begin ... end` is - it only works for `for` cycles, not for begin blocks)

Could you please explain a bit, what is this issue about?

---

<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:** [July 26, 2021, 5:13pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/4 "2021-07-26T17:13:44Z")

</div>

> [@tro3](#):
>
> Does the “migration” just mean a thread can wake up of any available thread, rather that that first assigned?

To being nitpick-y a bit, it means that “a _task_ can wake up on any available (OS) thread.”

Or more concretely, migration of task means

```julia
Threads.@spawn begin
    i = Threads.threadid()
    yield()
    j = Threads.threadid()
    @assert i == j
end

```

potentially _can_ throw after Julia 1.7. It has not been the case until 1.6.

> [@tro3](#):
>
> that would seem to make keeping Tasks off the primary more difficult

I think it’s fine for ThreadPools.jl since the `task.sticky = true` trick (or the public API `@async`) still works (i.e., the task will not be migrated).

> [@tisztamo](#):
>
> If that is true, then inserting gc safepoints will not be enough, yields are necessary

Yes, that s right. But GC was part of the discussion since it also can manifest as a scheduling problem. As you pointed out, we need to insert yield points (or support preemptive scheduling), _if_ we want to do everything in Julia’s task scheduler for achieving some kind of fairness. Another option is to just let the OS do it for a limited set of tasks, which is what JeffBezanson was suggesting.

---

<div class="post-metadata">

**Author:** ![tro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tro3/32/12355_2.png) [@tro3](https://discourse.julialang.org/u/tro3)\
**Post date:** [July 26, 2021, 5:36pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/5 "2021-07-26T17:36:15Z")

</div>

> [@tkf](#):
>
> To being nitpick-y a bit, it means that “a _task_ can wake up on any available (OS) thread.”

Yeah, yeah - that’s what I meant. 🙂 Thx

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [July 26, 2021, 6:59pm UTC](https://discourse.julialang.org/t/discussion-on-threadpools-jl/65283/6 "2021-07-26T18:59:02Z")

</div>

> [@tisztamo](#):
>
> what exactly `@threads begin ... end` is - it only works for `for` cycles, not for begin blocks)

I think that was a proposal to allow you to create a new thread to execute a begin block in. and not just a new task, but a new **OS thread** but I could be wrong?

I do think a macro `@withOSthread begin ... end` would be useful and I like using a name like that to make it clear what it does. If you want to spawn off a big computation that could take hours that’d be a hugely useful way to isolate that computation from other mixed tasks that might be going on.
