Description
Sorry to bother you again, it's just that I'm writing a sectino on multithreading and I'm still exploring this package.
I was surprised that tmap
doesn't automatically define thread-local variables inside anonymous functions.
# `temp` is not thread-local, wronly returns [2,2]
function = zeros(Int, 2)
temp = 0
tmap(1:2) do i
temp = i; sleep(i/2)
out[i] = temp
end
return out
end
println(foo())
For reference, LoopVectorization
automatically creates a thread-local variable when vmapntt
is used (the parallel version of vmapnt
)
# `temp` is thread-local, it correctly returns [1,2]
function = zeros(Int, 2)
temp = 0
vmapntt(1:2) do i
temp = i; sleep(i/2)
out[i] = temp
end
return out
end
println(foo())
Given that the package aims to be simple and user-friendly, maybe this behavior is undesirable?
I took the package as for people that want to apply multithreading, without being aware of the subtleties of multithreading.
If there are reasons for this choice, I think there should be a big warning in each function documentation.
I was wrongly taking for granted that this was internally handled, considering that false sharing issues were handled and that LoopVectorization
also deals with it.
I'm even more concerned about people not aware of these subtle issues, as it'd directly create a correctness issues. I can imagine that they'd think that the above implementation of tmap
is the same as the following.
# `temp` is thread-local, it correctly returns [1,2]
function compute(i, out)
temp = i; sleep(i/2)
out[i] = temp
end
function foo()
out = zeros(Int, 2)
temp = 0
tmap(i -> compute(i, out), 1:2)
return out
end
println(foo())
Just in case, I assumed the possibility that tforeach
wasn't necessarily defining thread-local variables, as it was presented as an alternative implementation to for-loops. However it wasn't the same intuition that I had for tmap
. Not saying that this is a general problem, but that maybe others will also have the same wrong impression.
Thanks again for all your efforts!!!