How can one use multi-threading with general iterators.
For ranges and arrays it’s very easy:
using Threads
result=Atomic{Int}(0)
for i in 1:1000_000
global result
atomic_add!(i)
end
# result.value == 500000500000 now
However trying the same with any more complicated iterator fails:
using Threads
result=Atomic{Int}(0)
@threads for i in Iterators.countfrom(1,1000_000)
global result
atomic_add!(i)
end
Error thrown in threaded loop on thread 2: MethodError(f=typeof(Base.length)(), args=(Base.Iterators.Count{Int64}(start=1, step=1000000),), world=0x0000000000006410)
Error thrown in threaded loop on thread 3: MethodError(f=typeof(Base.length)(), args=(Base.Iterators.Count{Int64}(start=1, step=1000000),), world=0x0000000000006410)
Error thrown in threaded loop on thread 1: MethodError(f=typeof(Base.length)(), args=(Base.Iterators.Count{Int64}(start=1, step=1000000),), world=0x0000000000006410)
Error thrown in threaded loop on thread 0: MethodError(f=typeof(Base.length)(), args=(Base.Iterators.Count{Int64}(start=1, step=1000000),), world=0x0000000000006410
I know multi-threading is still experimental so there might not be an easy way to do it.
For my calculation I want to reduce over the permutations of an array so shared memory is not even necessary and I could use multi-processing:
using Distributed
@distributed (+) for i in 1:1000_000
i
end
>> 500000500000
using Distributed
@everywhere using Combinatorics
#using other iterator because Iterators.Count doesn't support length
@distributed (+) for i in permutations([1,2,3,4,5,6])
sum(i)
end
On worker 2:
MethodError: no method matching getindex(::Combinatorics.Permutations{Array{Int64,1}}, ::Int64)
#35 at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Distributed/src/macros.jl:275
#112 at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Distributed/src/process_messages.jl:269
run_work_thunk at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Distributed/src/process_messages.jl:56
macro expansion at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Distributed/src/process_messages.jl:269 [inlined]
#111 at ./task.jl:259
Stacktrace:
[1] try_yieldto(::typeof(Base.ensure_rescheduled), ::Base.RefValue{Task}) at ./event.jl:196
[2] wait() at ./event.jl:255
[3] wait(::Condition) at ./event.jl:46
[4] wait(::Task) at ./task.jl:188
[5] fetch at ./task.jl:202 [inlined]
[6] iterate at ./generator.jl:47 [inlined]
[7] collect(::Base.Generator{Array{Task,1},typeof(fetch)}) at ./array.jl:606
[8] preduce(::Function, ::Function, ::Combinatorics.Permutations{Array{Int64,1}}) at /buildworker/worker/package_linux64/build/usr/share/julia/stdlib/v1.1/Distributed/src/macros.jl:263
[9] top-level scope at In[52]:1
It appears that the @distributed
macro wants to get the loop elements with getindex calls, which aren’t defined for simple iterators.
Is there a way to make this work? The number of permutations I get are quite big and it is absolutely not necessary to have them collected in an array. It still would be nice to get some parralelization.