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

Add @threads :dynamic #40908

Closed
wants to merge 2 commits into from

Conversation

jks-liu
Copy link

@jks-liu jks-liu commented May 22, 2021

Better balance if tasks in iteration have different time costs.

julia> Threads.nthreads()
8

julia> function foo(x)
       if x <= 8
           sleep(1)
       end
   end
foo (generic function with 1 method)

julia> @time Threads.@threads for i in 1:16
       foo(i)
   end

  2.055390 seconds (17.37 k allocations: 1023.688 KiB, 0.00% compilation time)

julia> @time Threads.@threads :dynamic for i in 1:16
       foo(i)
   end
  1.052706 seconds (70.21 k allocations: 3.986 MiB, 0.39% compilation time)

lenr = length(r)
while (i = atomic_add!(idx, UInt(1))) <= lenr
local $(esc(lidx)) = @inbounds r[i]
$(esc(lbody))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will need to come up with a different approach here. We need to avoid generating two copies of the code: the code size is 2^n for nesting depth n. Even though nesting @threads loops is not common, avoiding this is the best practice.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the compiler be able to constprop the schedule to delete the branch not taken?

Copy link
Contributor

@chriselrod chriselrod May 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, I'd just check if schedule === :dynamic or schedule === :static.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for late reply.
I think the :dynamic version is just like the default version which only use multi-threads in thread 1. So I don't think the 2^n thing will happen.
This is why I said ":dynamic creates one task per thread if possible" in the doc string.


The default schedule (used when no `schedule` argument is present) is subject to change.

!!! compat "Julia 1.5"
The `schedule` argument is available as of Julia 1.5.

!!! compat "Julia 1.7"
The `schedule` argument supports `:dynamic` as of Julia 1.7.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 space indent

@JeffBezanson JeffBezanson added the multithreading Base.Threads and related functionality label May 24, 2021
@JeffBezanson
Copy link
Member

Welcome, and thanks for working on this! Very good first PR.

I think we'll want to discuss exactly how the scheduling should work. You version works fine for small iteration counts, but I wonder if we still want to do some chunking to prevent excessive overhead.

@lstagner
Copy link
Contributor

I was thinking that it would be nice to be able to specify how many threads I want to split the loop into e.g.

@threads 4 for i=1:100 # <--- split loop into 4 tasks
    do_work()
end

@IanButterworth
Copy link
Member

A similar approach has been implemented in #43919 and the current idea is to develop more advance dynamic scheduling into that namespace, or new schedule names

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
multithreading Base.Threads and related functionality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants