I need to perform a map-reduce involving different variables, as in
a = b = 0
for n = 1:10
a += n
b += n*n
end
I want to do it in parallel, using @distributed
, and I think a possible solution involves the definition of a new type to hold both values:
@everywhere struct T
a::Int64
b::Int64
end
@everywhere Base.:+(x::T, y::T) = T(x.a + y.a, x.b + y.b)
x = T(0, 0)
result = @distributed (+) for n = 1:10
T(n, n*n)
end
That is a little involved, but I could not find a better solution…
My problem is that some of the variables I need to reduce are actually arrays and are therefore mutable. This makes the situation unclear even in the case of a single array. For example, if I start julia with julia -p 4
to have 4 workers, than this code does not perform as expected:
a = zeros(1)
@distributed (+) for n=1:10
a[1] = n
a
end
The result I get is 59 instead of the expected 55. Everything is fine if I use, as last line in the loop, copy(a)
, but this is clearly not optimal for the performance.
As far as I understand, this issue is related to the following piece of code:
a = zeros(1)
(a[1] = 1; a) + (a[1] = 2; a) ==> 4
In other words, a
is modified by the last block, and the value 2
is duplicated. Is there a simple way for me to avoid this sort of issues? Wouldn’t it be a good idea anyway to have a way to specify reduction variables inside a @distributed
loop, similarly to the way OpenMP works?