# Multi-threaded code with :dynamic scheduler and mutable data

**URL:** <https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887>\
**Category:** General Usage\
**Tags:** multithreading\
**Created:** [April 25, 2023, 6:33am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887 "2023-04-25T06:33:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![lijas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lijas/32/20023_2.png) [@lijas](https://discourse.julialang.org/u/lijas)\
**Post date:** [April 25, 2023, 6:33am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/1 "2023-04-25T06:33:26Z")

</div>

I have a loop which I am currently multi-threading using the :static scheduler:

```julia
threadcache = [create_cache() for i in 1:Threads.nthreads()]
Threads.@threads :static for i in 1:...
    data = threadcache[Threads.threadid()]
    result = compute_stuff(..., data) #data will be mutated in this function
    store_results[i] = result #Maybe save the result in a vector
end

```

where `create_cache()` creates a struct with some pre-allocated arrays which will be mutated in `compute_stuff()`.

The function `compute_stuff` does not always take the same amount of time to run, so I think I could benefit a bit from using the `:dynamic` scheduler (or perhaps using `@sync ...@spawn`). The docs also seems to discourage the use of :static scheduling.

The problem is that I don’t understand how to multi-thread this with dynamic scheduler when I have the mutable data `threadcache[Threads.threadid()]`, since dynamic scheduling do not guarantee that `Threads.threadid()` is constant during an iteration.

Can anyone help me multi-thread this with either `:dynamic` scheduler or `@spawn ... @sync`.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [April 25, 2023, 7:34am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/2 "2023-04-25T07:34:00Z")

</div>

Something like this?

```julia
threadcache = [create_cache() for i in 1:Threads.nthreads()]
idx = Threads.Atomic{Int}(N)
@sync for thr in eachindex(threadcache)
    Threads.@spawn begin
        data = threadcache[$thr]
        while (i = Threads.atomic_sub!(idx, 1)) > 0
            result = mutate(i, data)
            store_result[i] = result
        end
    end
end

```

---

<div class="post-metadata">

**Author:** ![lijas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lijas/32/20023_2.png) [@lijas](https://discourse.julialang.org/u/lijas)\
**Post date:** [April 26, 2023, 6:02am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/3 "2023-04-26T06:02:35Z")

</div>

Thanks! But it feels like that this is more complicated than what should be needed? 😅

Refining my google search a bit, I found this [post](https://discourse.julialang.org/t/pattern-for-managing-thread-local-storage/54023) which uses Channels instead. I have never used channels before, but it looks a bit simpler. I will try it out

It feels like my problem/questions would be a pretty common thing people would want to do, so I am a bit surprised that it is difficult to find information about it.

---

<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:** [April 26, 2023, 9:27am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/4 "2023-04-26T09:27:11Z")

</div>

regarding the use of Channels, let me link to this [Post](https://discourse.julialang.org/t/floops-init-allocate-only-once/93500/13), which has a nice code example that pretty much directly applies to what you are trying to do here

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 26, 2023, 11:50am UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/5 "2023-04-26T11:50:17Z")

</div>

See: [Home · ChunkSplitters.jl](https://m3g.github.io/ChunkSplitters.jl/stable/)

And here there is a discussion exactly about load balancing in this context: [Parallel load balancing · JuliaNotes.jl](https://m3g.github.io/JuliaNotes.jl/stable/loadbalancing/)

But basically, you can do this:

```julia
using ChunkSplitters
function run(;nchunks=Threads.nthreads())
    threadcache = [create_cache() for i in 1:nchunks]
    @sync for (i_range, i_chunk) in chunks(data, nchunks)
        @spawn for i in i_range
            data = threadcache[ichunk]
            result = compute_stuff(..., data) #data will be mutated in this function
            store_results[i] = result #Maybe save the result in a vector
        end
    end
    return store_results
end

```

and you can increase `nchunks` to be of any size, for instance 10 times `nthreads()`, to take advantage of the dynamic scheduling while at the same time being thread-safe by not using `threadid()`

---

<div class="post-metadata">

**Author:** ![lijas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lijas/32/20023_2.png) [@lijas](https://discourse.julialang.org/u/lijas)\
**Post date:** [April 26, 2023, 12:25pm UTC](https://discourse.julialang.org/t/multi-threaded-code-with-dynamic-scheduler-and-mutable-data/97887/6 "2023-04-26T12:25:09Z")

</div>

This is great, thank you. I will try ChunkSplitters.jl and see how it works in my code!
