According to the docs for Threads.@spawn
, you can interpolate an argument via $
and it will spawn the task with a copy of the variable. I have found that when I use a custom struct
that use SparseArrays, that this behavior does not work as expected:
using SparseArrays, Base.Threads
struct C
sa::SparseMatrixCSC{Float64,Int64}
end
c = C(zeros(Float64, (10,10)))
c.sa[1,1] = 5.0
function func(f::C)
f.sa[1,1] = 80.0
f.sa[2,1] = 10.0
f
end
c_ = Threads.@spawn begin
sleep(5)
func($c)
end
c
#-- C(
#-- [1, 1] = 5.0)
fetch(c_)
#-- C(
# -- [1, 1] = 80.0
# -- [2, 1] = 10.0)
c
#-- C(
# -- [1, 1] = 80.0
# -- [2, 1] = 10.0)
In spite of using $ to interpolate, the spawned task ends up mutating the original instance of the structure. This does not seem to be an issue with SparseArrays:
struct CS
f1::Array{Int64,1}
f2::Array{Float64, 1}
f3::String
end
x = CS(zeros(Int64,5),zeros(Float64, 5),"yes")
function func!(x::CS)
x.f1[1] = 80
x.f2[1] = 55.0
x
end
f_ = Threads.@spawn begin
sleep(5)
func!($x)
end
fetch(f_)
# CS([80, 0, 0, 0, 0], [55.0, 0.0, 0.0, 0.0, 0.0], "yes")
x
# CS([80, 0, 0, 0, 0], [55.0, 0.0, 0.0, 0.0, 0.0], "yes")
# happens even without structures:
x = [1,2,3]
function func!(x::Array{Int64,1})
x[1] = 10
x
end
f_ = Threads.@spawn begin
sleep(5)
func!($x)
end
fetch(f_)
# 3-element Array{Int64,1}:
# 10
# 2
# 3
x
# 3-element Array{Int64,1}:
# 10
# 2
# 3
My questions: 1) is this a bug (and should I open an issue on github), and 2) is there a workaround, or should I consider not use sparse arrays?
I could manually copy the sparse array and pass that as the arg:
struct C
sa::SparseMatrixCSC{Float64,Int64}
end
c = C(zeros(Float64, (10,10)))
c.sa[1,1] = 5.0
function func(f::C)
f.sa[1,1] = 80.0
f.sa[2,1] = 10.0
f
end
c_ = Threads.@spawn begin
sleep(5)
cc = C(copy(c.sa))
func(cc)
end
c
#-- C(
#-- [1, 1] = 5.0)
fetch(c_)
#-- C(
# -- [1, 1] = 80.0
# -- [2, 1] = 10.0)
c
#-- C(
#-- [1, 1] = 5.0)
It’s unclear to me how different this copy approach is to what the interpolation was supposed to accomplish, and whether it may be incurring more overhead. Are there good ways to measure this? Not sure how to best measure this.