# Safe loop with push! multi-threading

**URL:** <https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892>\
**Category:** Performance\
**Tags:** performance, parallel\
**Created:** [June 22, 2020, 8:56pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892 "2020-06-22T20:56:33Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![mleprovost](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mleprovost/32/7166_2.png) [@mleprovost](https://discourse.julialang.org/u/mleprovost)\
**Post date:** [June 22, 2020, 8:56pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/1 "2020-06-22T20:56:33Z")

</div>

Hello,

I would like to use multi-threading to speed-up a for loop.  
For each instance, an expensive computation is done and then the result is pushed at the end of an array. Here is toy example:

```julia
x = collect(1:10)
f(x) = x+1
xlist = []
idx = []
Threads.@threads for i =1:length(x)
    xnew = f(x[i])
    push!(xlist, deepcopy(xnew))
    push!(idx, deepcopy(i))
end

```

However, the previous is not safe for multi-threading  
`xlist` is different at each run and the elements are not ordered.

I have tried ThreadedIterables [https://github.com/marekdedic/ThreadedIterables.jl](https://github.com/marekdedic/ThreadedIterables.jl) but I don’t get any speed-up.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [June 22, 2020, 9:04pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/2 "2020-06-22T21:04:36Z")

</div>

I don’t think you need deepcopy but you can’t just `push!` in this case because the operation is not atomic, try this instead:

> [@Thread-safe array building](https://discourse.julialang.org/t/thread-safe-array-building/3275/2):
>
> Create nthreads() number of arrays and push to them based on threadid().

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [June 22, 2020, 9:30pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/3 "2020-06-22T21:30:37Z")

</div>

An approach I like to do is have a Channel where the result is pushed into and spawn a task for the multithreaded loop. This way, a different task can `take!` from the channel and finish the aggregation safely.

---

<div class="post-metadata">

**Author:** ![mleprovost](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mleprovost/32/7166_2.png) [@mleprovost](https://discourse.julialang.org/u/mleprovost)\
**Post date:** [June 22, 2020, 9:31pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/4 "2020-06-22T21:31:28Z")

</div>

I am trying to adapt the code of [Thread-safe array building - #2 by yuyichao](https://discourse.julialang.org/t/thread-safe-array-building/3275/2) for `Array{Float64,1}`:

```julia
num_monte = Int(1e6)
solution_data = Vector{Array{Float64,1}}()
for i in 1:Threads.nthreads()
  push!(solution_data, Array{Float64,1}[])
end
Threads.@threads for i in 1:num_monte
  push!(solution_data[Threads.threadid()],[1.0; 2.0])
end

```

TaskFailedException:  
MethodError: Cannot `convert` an object of type Array{Float64,1} to an object of type Float64  
Closest candidates are:  
convert(::Type{T}, !Matched::Ratios.SimpleRatio{S}) where {T\<:AbstractFloat, S} at /home/mat/.julia/packages/Ratios/uRs4y/src/Ratios.jl:14  
convert(::Type{T}, !Matched::T) where T\<:Number at number.jl:6  
convert(::Type{T}, !Matched::Number) where T\<:Number at number.jl:7  
…  
Stacktrace:  
[1] push!(::Array{Float64,1}, ::Array{Float64,1}) at ./array.jl:912  
[2] macro expansion at ./In[87]:7 [inlined]  
[3] (::var"#804#threadsfor\_fun#28"{UnitRange{Int64}})(::Bool) at ./threadingconstructs.jl:61  
[4] (::var"#804#threadsfor\_fun#28"{UnitRange{Int64}})() at ./threadingconstructs.jl:28

Stacktrace:  
[1] wait(::Task) at ./task.jl:267  
[2] macro expansion at ./threadingconstructs.jl:69 [inlined]  
[3] macro expansion at ./util.jl:175 [inlined]  
[4] top-level scope at ./In[87]:6

---

<div class="post-metadata">

**Author:** ![mleprovost](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mleprovost/32/7166_2.png) [@mleprovost](https://discourse.julialang.org/u/mleprovost)\
**Post date:** [June 22, 2020, 9:33pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/5 "2020-06-22T21:33:41Z")

</div>

Thank you for your answer,

I am not familiar with `Channel` in Julia, can you Channel-style rewriting of the toy problem?

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [June 22, 2020, 9:35pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/6 "2020-06-22T21:35:25Z")

</div>

In this particular example, the best approach would probably be to preallocate `xlist` and `idx`:

```julia
x = collect(1:10)
f(x) = x+1
xlist = Array{Int}(undef, length(x))
idx = Array{Int}(undef, length(x))
Threads.@threads for i =1:length(x)
    xnew = f(x[i])
    xlist[i] = xnew
    idx[i] = i
end

```

Preallocating arrays should always be prefered if you know the size in advance, since when resizing arrays, often times new memory needs to be allocated, which is quite expensive.

---

<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:** [June 22, 2020, 9:45pm UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/7 "2020-06-22T21:45:43Z")

</div>

The code in the OP tries to implement threaded `map`. I recommend using existing solutions. For example:

- [GitHub - tro3/ThreadPools.jl: Improved thread management for background and nonuniform tasks in Julia. Docs at https://tro3.github.io/ThreadPools.jl](https://github.com/tro3/ThreadPools.jl)
- [GitHub - mohamed82008/KissThreading.jl: Simple patterns supporting working with threads in Julia](https://github.com/mohamed82008/KissThreading.jl)
- [GitHub - baggepinnen/ThreadTools.jl: Some tools for working with threads in Julia](https://github.com/baggepinnen/ThreadTools.jl)
- [GitHub - Jutho/Strided.jl: A Julia package for strided array views and efficient manipulations thereof](https://github.com/Jutho/Strided.jl)
- [GitHub - tkf/ThreadsX.jl: Parallelized Base functions](https://github.com/tkf/ThreadsX.jl)

> [@simeonschaub](#):
>
> Preallocating arrays should always be prefered if you know the size in advance

You also need to know the output type of `f` which is impossible in general.

---

<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:** [June 23, 2020, 2:36am UTC](https://discourse.julialang.org/t/safe-loop-with-push-multi-threading/41892/8 "2020-06-23T02:36:01Z")

</div>

From [GitHub - tro3/ThreadPools.jl: Improved thread management for background and nonuniform tasks in Julia. Docs at https://tro3.github.io/ThreadPools.jl](https://github.com/tro3/ThreadPools.jl) how about:

```julia
julia> ThreadPools.tmap(collect(enumerate(x))) do (i,xx)
           deepcopy(i), deepcopy(f(xx))
       end
10-element Array{Tuple{Int64,Int64},1}:
 (1, 2)
 (2, 3)
 (3, 4)
 (4, 5)
 (5, 6)
 (6, 7)
 (7, 8)
 (8, 9)
 (9, 10)
 (10, 11)

```

Each entry is a separate thread. Order is guaranteed.
