# Assignment not effective in `@spawn` in function

Define a simple function copying the contents of one array to another:

``````function copy_array!(array_t::AbstractArray, array_s::AbstractArray)
array_t .= array_s

return nothing
end
``````

The following function performs the above function with and without `@spawn` and compares the results:

``````using Base.Threads: @spawn
using LinearAlgebra: norm

function test_spawned_copy()
N = 1000
A = rand(N);
B = zeros(N);
C = zeros(N);

copy_array!(B, A)
@spawn copy_array!(C, A)

println("‖A‖ = \$(norm(A))\n‖B‖ = \$(norm(B))\n‖C‖ = \$(norm(C))")
end
``````

Executing the above function, we realize that `copy_array!` is not effective with `@spawn`:

``````julia> test_spawned_copy()
‖A‖ = 18.176417571506622
‖B‖ = 18.176417571506622
‖C‖ = 0.0  # assignment in array C didn't occur
``````

However, if the contents of the above test function are executed in REPL, `copy_array!` produces the same results with and without `@spawn`:

``````julia> N = 1000;

julia> A = rand(N);

julia> B = zeros(N);

julia> C = zeros(N);

julia> copy_array!(B, A);

julia> @spawn copy_array!(C, A);

julia> println("‖A‖ = \$(norm(A))\n‖B‖ = \$(norm(B))\n‖C‖ = \$(norm(C))");
‖A‖ = 18.054455128272014
‖B‖ = 18.054455128272014
‖C‖ = 18.054455128272014  # assignment in array C did occur
``````

Is this an expected result? Here is the Julia version:

``````julia> VERSION
v"1.5.4-pre.0"
``````

It seems that the @spawn macro from Distribution is used (sometimes).
If you do in a fresh REPL:

``````function copy_array!(array_t::AbstractArray, array_s::AbstractArray)
array_t .= array_s
return nothing
end

function test_spawned_copy()
n = 10
c = zeros(n);
d = zeros(n);
@spawn copy_array!(c, rand(n))
(c,d)
end

(c,d)=test_spawned_copy()
``````

you get:

``````([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [0.5282095840733001, 0.5556105622927612, 0.20150965328960568, 0.31812680241750946, 0.46483288319514715, 0.013753794057519642, 0.6303004740215832, 0.22042140183053638, 0.9973105034241585, 0.346232614933345])
``````

``````using Base.Threads: @spawn
``````

you get:

``````([0.35270524970982176, 0.7986731832036376, 0.4356428356231954, 0.4497905410479941, 0.3878368060348809, 0.11946402924101096, 0.6408044427105426, 0.6883479688491787, 0.7404863070919507, 0.31914232478228866], [0.004167961824976141, 0.5848904661256766, 0.5722504383047835, 0.9284901252145417, 0.677612496185245, 0.715904376389237, 0.9944319571686495, 0.005437923152379565, 0.1644076654195401, 0.17196103627138593])
``````

Again, a fresh REPL:

``````function copy_array!(array_t::AbstractArray, array_s::AbstractArray)
array_t .= array_s
return nothing
end
n = 10
c = zeros(n);
@which( @spawn copy_array!(c, rand(n)) )
``````

gives

``````julia> @which( @spawn copy_array!(c, rand(n)) )
@spawn(__source__::LineNumberNode, __module__::Module, expr) in Distributed at C:\Users\oheil\AppData\Local\Programs\Julia 1.5.3\share\julia\stdlib\v1.5\Distributed\src\macros.jl:46
``````

That `Distributed.@spawn` doesn’t work is understandable, as different processes are used where data is copied into the new process.
So, the solution is, always make sure, that `Threads.@spawn` is used.

Of course the REPL must be started with Threads and/or Processes:
`julia.exe -t auto -p auto`

Isn’t this a race condition? You are not waiting for the task to finish.

2 Likes

Thanks, @kristoffer.carlsson! For other people, the solution is to modify `test_spawned_copy` using `wait` as follows:

``````function test_spawned_copy()
N = 1000
A = rand(N);
B = zeros(N);
C = zeros(N);

copy_array!(B, A)
t = @spawn copy_array!(C, A)
wait(t)

println("‖A‖ = \$(norm(A))\n‖B‖ = \$(norm(B))\n‖C‖ = \$(norm(C))")
end
``````