-
Notifications
You must be signed in to change notification settings - Fork 501
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
cooperative yield in ThreadPool::install() causes unexpected behavior in nested pools #1105
Comments
I do think yielding is the appropriate default behavior, and documentation PRs are fine to clarify this. I think we could also add a variant or two of
BTW, your |
@cuviper, I appreciate your explanation of the
In the simplest case:
There is no need to make IMHO, if we were writing Rayon from scratch, I would suggest making all yields explicit. The default behavior would then be expressed as follows. Making the yield explicit makes the behavior obvious to the programmer, and it also gives the programmer the choice of moving
I have to agree, but only because changing the behavior of |
Since So when I talk about yielding vs. blocking here, I'm only talking about what the thread should do while it waits, but we do have to wait for We've also had discussions about actual
The design is the more interesting part that needs discussion. Regarding Another idea that I've raised before is that we could have a kind of "critical section" call, inhibiting all work-stealing on that thread until that call returns. (Possibly with some nuance like allowing local work-stealing of work queued while in that call.) This might be a better way to have broad impact without forking a bunch of APIs. If we decide on just adding rayon/rayon-core/src/registry.rs Lines 486 to 504 in 7449d7d
The cold path currently |
Ah, I stand corrected. Since
I'll refactor my code with EDIT It looks like calling
This sounds difficult to implement, but it sounds like it would be the most ergonomic solution in the long term. EDIT Might still need a non-yielding |
Document implicit yield in install() per #1105
It appears calls to
ThreadPool::install(op)
will start runningop
inside the child thread pool and then cooperatively yield, potentially switching to a different task. This causes unexpected behavior with nested iterators using thread pools. It would be nice if rayon didn't yield onThreadPool::install()
, or if the authors believe that it should yield, to place some kind of warning in the documentation forThreadPool::install()
.Consider the following example. You have an outer loop that performs some operation that requires a lot of memory. You have an inner loop that uses a lot of cpu but is memory-efficient. To avoid unbounded memory growth, you will run the outer and inner loops in separate thread pools where
ncpus_outer
is a small number andncpus_inner
is a big number.Suppose
ncpus_outer
is equal to one. You might reasonably expect that only onebar
will be allocated at any given time, giving you control over memory use. However, the output of the program may actually look like:This is possible because, rather than blocking until
pool_inner.install()
returns, the outer thread pool will yield and cooperatively schedule another iteration of the outer loop on the same thread. This gives you essentially zero control over how many instances ofbar
will be allocated at a given time.This is an even bigger problem if you have to do some kind of synchronization (yes there are real uses cases for this):
The outer thread pool yields to a different task before releasing the mutex, likely leading to a deadlock unless it switches back to the task holding the mutex before it runs out of threads in the outer pool.
The text was updated successfully, but these errors were encountered: