# Elementwise multiplication of arrays across many cores

**URL:** https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222
**Category:** General Usage
**Tags:** parallel
**Created:** [April 14, 2017, 6:29pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222 "2017-04-14T18:29:09Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![garrison](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/garrison/32/209519_2.png) [@garrison](https://discourse.julialang.org/u/garrison)
#### Post date: [April 14, 2017, 6:29pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/1 "2017-04-14T18:29:09Z")

</div>

I have two parallel arrays `a` and `b` of type `Vector{Complex128}`, and each of them is very large (say, each contains `2^30` elements, thus each requires around 16 GB of RAM). I would like to multiply these arrays elementwise on a machine with many cores available. The obvious way is to use the “dot” syntax

```
a .*= b

```

but this only uses a single core. At the moment, [there is no parallel version of `broadcast`](https://github.com/JuliaLang/julia/issues/19777), so I am trying to figure out what the next best alternative may be. As far as I can tell, none of the BLAS operations fit this pattern (though `BLAS.gbmv!` comes close, except I would need to pass `a` as two different arguments, and I am pretty sure BLAS assumes non-overlapping memory). I also tried using `Threads.@threads` but this did not speed things up (I can elaborate more on this if necessary).

What is the most efficient way to implement such a calculation? I’m getting close to implementing this part of the calculation as a kernel written in C using pthreads.

Thanks!

---

<div class="post-metadata">

### Author: ![garrison](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/garrison/32/209519_2.png) [@garrison](https://discourse.julialang.org/u/garrison)
#### Post date: [April 14, 2017, 6:31pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/2 "2017-04-14T18:31:33Z")

</div>

By the way, here is my code testing `@threads`:

```julia
function f1!(a, b)
    a .*= b
    a
end

function f2!(a, b)
    Threads.@threads for i in 1:4
        s = div(length(a), 4)
        r1, r2 = s*(i-1)+1, s*i
        @inbounds a[r1:r2] .*= @view b[r1:r2]
    end
    a
end

for N in [8, 25]
    @show N
    a = rand(Complex128, 2 ^ N)
    b = rand(Complex128, 2 ^ N)
    @time f1!(a, b)
    @time f2!(a, b)
end

```

which I run with `JULIA_NUM_THREADS=4`.

EDIT: Oddly enough, even `f1!` allocates, which I do not understand:

```julia
N = 8
  0.000001 seconds (2 allocations: 4.156 KB)
  0.061202 seconds (47.53 k allocations: 2.154 MB)
N = 25
  0.757689 seconds (3 allocations: 512.000 MB, 6.71% gc time)
  2.006967 seconds (31 allocations: 1.375 GB, 19.78% gc time)

```

---

<div class="post-metadata">

### Author: ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)
#### Post date: [April 14, 2017, 6:40pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/3 "2017-04-14T18:40:37Z")

</div>

> [@garrison](#):
>
> ```julia
> function f2!(a, b)
> Threads.@threads for i in 1:4
> s = div(length(a), 4)
> r1, r2 = s*(i-1)+1, s*i
> @inbounds a[r1:r2] .*= @view b[r1:r2]
> end
> a
> end
> 
> ```

This is the wrong way to use threads, do

```julia
Threads.@threads for i in 1:length(a)
    @inbounds a[i] *= b[i]
end

```

Directly.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 14, 2017, 6:40pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/4 "2017-04-14T18:40:57Z")

</div>

> [@garrison](#):
>
> Oddly enough, even f1! allocates, which I do not understand:

`.*` is only in-place in Julia 0.6

---

<div class="post-metadata">

### Author: ![garrison](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/garrison/32/209519_2.png) [@garrison](https://discourse.julialang.org/u/garrison)
#### Post date: [April 14, 2017, 6:46pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/5 "2017-04-14T18:46:10Z")

</div>

Thanks @yuyichao and @stevengj, that solves both of my problems.

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [April 14, 2017, 6:51pm UTC](https://discourse.julialang.org/t/elementwise-multiplication-of-arrays-across-many-cores/3222/6 "2017-04-14T18:51:48Z")

</div>

> [@garrison](#):
>
> `@time f1!(a, b)`

I would also recommend `using BenchmarkTools` and then doing `@btime f1!($a, $b)`, so it will be more sophisticated about collecting timing statistics.

That being said, I’m pretty surprised that you are trying to multi-thread such a simple operation. Multi-threading will be much more effective if you are doing more computation on each data item, so that the overhead of memory access (which doesn’t parallelize as well due to contention) is less. If you have a real application (rather than just doing synthetic benchmarks), I would strongly recommend trying to multi-thread at a coarser level. (i.e. don’t try to multi-thread individual vector operations: fuse multiple operations together into a single `@threads` loop).
