Yes.
You could try adding let
blocks.
Note that Threads.@spawn
has sugar where using $
on variables automatically creates let blocks for you:
julia> @macroexpand Threads.@spawn foo($x)
quote
#= threadingconstructs.jl:229 =#
let var"##394" = x
#= threadingconstructs.jl:230 =#
local var"#14#task" = Base.Threads.Task((()->begin
#= threadingconstructs.jl:226 =#
foo(var"##394")
end))
#= threadingconstructs.jl:231 =#
(var"#14#task").sticky = false
#= threadingconstructs.jl:232 =#
if $(Expr(:islocal, Symbol("##sync#48")))
#= threadingconstructs.jl:233 =#
Base.Threads.put!(var"##sync#48", var"#14#task")
end
#= threadingconstructs.jl:235 =#
Base.Threads.schedule(var"#14#task")
#= threadingconstructs.jl:236 =#
var"#14#task"
end
end
But this isn’t supported for Threads.@threads
, although it’s probably easy enough to manually create let
blocks, unless you have an absurd number of variables (fun fact: let
used to be O(N^2)
in number of variables, until very recent versions of Julia [1.8+?], where it is now O(N)
, thanks to some code with thousands of let
causing this to actually be problematic). This is the classic workaround.
You could also manually chunk your iteration range, perhaps separating the code that iterates over a chunk into a separate function, and use @spawn
. I also often do this anyway when I want more control over task-local state, e.g. rngs. @spawn
is of course more dynamic than @threads
, which you may or may not want.