Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iterators like pemutations do not support @threads #165

Open
Marco-Congedo opened this issue May 3, 2024 · 2 comments
Open

iterators like pemutations do not support @threads #165

Marco-Congedo opened this issue May 3, 2024 · 2 comments

Comments

@Marco-Congedo
Copy link

iterators like pemutations do not support @threads

julia> P=permutations(1:3)
Combinatorics.Permutations{UnitRange{Int64}}(1:3, 3)

julia> for p∈P
       println(p)
       end
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

julia> @threads for p∈P
       println(p)
       end

ERROR: TaskFailedException

nested task error: MethodError: no method matching firstindex(::Combinatorics.Permutations{UnitRange{Int64}})

Closest candidates are:
  firstindex(::Any, ::Any)
   @ Base abstractarray.jl:447
  firstindex(::Base.JuliaSyntax.SourceFile)
   @ Base C:\workdir\base\JuliaSyntax\src\source_files.jl:131
  firstindex(::Markdown.MD)
   @ Markdown C:\Users\congedom\AppData\Local\Programs\Julia-1.10.0\share\julia\stdlib\v1.10\Markdown\src\parse\parse.jl:27
  ...

Stacktrace:
 [1] (::var"#539#threadsfor_fun#148"{var"#539#threadsfor_fun#147#149"{…}})(tid::Int64; onethread::Bool)
   @ Main .\threadingconstructs.jl:199
 [2] #539#threadsfor_fun
   @ Main .\threadingconstructs.jl:181 [inlined]
 [3] (::Base.Threads.var"#1#2"{var"#539#threadsfor_fun#148"{var"#539#threadsfor_fun#147#149"{…}}, Int64})()
   @ Base.Threads .\threadingconstructs.jl:153

...and 5 more exceptions.

@adknudson
Copy link

I think in general, threaded for-loops don't work on non-indexible collections. This happens in Base as well:

# This works because you can index into a Range object
Base.Threads.@threads for p  1:4
    println(p)
end

# This throws the same TaskFailedException as in your example
Base.Threads.@threads for p  Iterators.product(1:2, 1:2)
    println(p)
end

Combinatorics.permutations creates an iterator that tracks state through a vector of Ints, and so it doesn't use linear indexing, which is probably what the @threads macro expects:

function Base.iterate(p::Permutations, state::Vector{Int}=fill(firstindex(p.data), p.length))
next_permutation!(state, firstindex(p.data), lastindex(p.data))
if first(state) > lastindex(p.data)
return nothing
end
[p.data[i] for i in state], state
end

@adknudson
Copy link

If your state is small enough to fit in memory, then you can collect the permutations and call @threads on the returned collection:

P = permutations(1:3)

@threads for p in collect(P)
    println(p)
end

Just be sure that the time saved by threading can offset the overhead of collecting the permutations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants