Skip to content

Add yield_now and yield_local #1026

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

Merged
merged 3 commits into from
Mar 2, 2023
Merged

Add yield_now and yield_local #1026

merged 3 commits into from
Mar 2, 2023

Conversation

cuviper
Copy link
Member

@cuviper cuviper commented Feb 26, 2023

  • yield_now looks for work anywhere in the thread pool and executes it.
  • yield_local only looks in the thread-local deque (including broadcasts).

In either case, they return:

  • Some(Yield::Executed) if work was found and executed.
  • Some(Yield::Idle) if no work was found in their pool/thread.
  • None if the current thread is not part of a thread pool.

These do not call std::thread::yield_now(), but the docs suggest polling loops might want to add that as a fallback.

@adamreichold
Copy link
Collaborator

Is there some peripheral motivation for using Option<bool> instead of a dedicated enum with three variants?

@cuviper
Copy link
Member Author

cuviper commented Feb 26, 2023

We already use Option<_> for other functions that return None if you're not in a pool, like current_thread_index. Is there an advantage you see to having a dedicated enum?

@cuviper cuviper linked an issue Feb 26, 2023 that may be closed by this pull request
@adamreichold
Copy link
Collaborator

adamreichold commented Feb 26, 2023

Is there an advantage you see to having a dedicated enum?

Mainly usability, e.g. if yield_now() == NoWorkFound is easier to get right than if !yield_now(), so basically the same reason ControlFlow exists which has personally saved me several times when writing traversals.

But something like Option<YieldResult> would serve the same purpose, so this is probably more about bool than Option.

@cuviper
Copy link
Member Author

cuviper commented Feb 26, 2023

Option<YieldResult> sounds ok, as does NoWorkFound, but should the true case be WorkFound or Yielded, or something else? And should this be #[non_exhaustive]? Or we can go opaque like FnContext and bikeshed method names instead.

(So one reason to avoid all this was laziness.. 😅 )

@adamreichold
Copy link
Collaborator

adamreichold commented Feb 26, 2023

but should the true case be WorkFound or Yielded, or something else?

YieldResult and NoWorkFound were actually not really thought through, I was mainly paraphrasing your cover letter here which would then suggest WorkFoundAndExecuted for the true case. :-)

I'd also argue that Yielded is always applicable since this is what the application does (yielding to Rayon's scheduler) and whether that leads to additional work being executed is just one possible outcome of yielding.

This would lead me personally to something like

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Yielded {
  ExecutedJob,
  NoJobFound,
}

which tries to be sufficiently short and pick up the Job terminology used by Rayon's implementation.

And should this be #[non_exhaustive]?

I'd say that since Option<bool> would also commit this API to the three specified outcomes, #[non_exhaustive] does not seem appropriate.

@cuviper
Copy link
Member Author

cuviper commented Feb 27, 2023

We do speak of "jobs" in docs a lot, or "work", but the only thing I found in a public API name was "tasks" in current_thread_has_pending_tasks. I think it reads well enough without picking a term here -- for the moment I went with Yield::Executed and Yield::Idle. When I wrote it in docs, Yielded::* felt awkward, but I haven't decided yet. Idle might also be implying too much, so maybe I'll go back to NotFound.

(It would probably be nice if we were more consistent in docs, but it's not a breaking change to clean that up later.)

@adamreichold
Copy link
Collaborator

Personally, I am perfectly happy with the current state as it is certainly much more expressive than true and false. Thank you for considering the change.

@cuviper
Copy link
Member Author

cuviper commented Feb 27, 2023

Thank you for your feedback! And since you've shown interest, I would also love to hear if you're thinking about concrete use-cases for this.

@adamreichold
Copy link
Collaborator

adamreichold commented Feb 27, 2023

And since you've shown interest, I would also love to hear if you're thinking about concrete use-cases for this.

I have to admit that this was a "accidental review" out of curiosity. While I have had my run-ins with bool-typed control flow indicators, I have no personal use case where I would want to yield into Rayon's thread pool.

Personally, I would even go as far as calling such an API a bit "unrayonic" meaning that I go for Rayon precisely in those cases where I do not want to worry about thread scheduling and task placement but just want my data to be distributed to the available CPU without manual intervention. And while I have written synchronization involving park, yield_now and friends, this was always in code bases which tried to take full control of the usage of threads, e.g. simulations with one thread per CPU and different parts of the simulated world being handled by a fixed thread.

But of course, other reporters do seem to have these requirements as per #548. Sorry for not being able to shed more on these use cases.

@cuviper
Copy link
Member Author

cuviper commented Feb 27, 2023

No worries, "I wouldn't use this" is valid feedback as well, thanks!

@cuviper
Copy link
Member Author

cuviper commented Mar 2, 2023

I'm going ahead with this. The rough idea is something folks have asked for in the past, and even if it turns out unused, I don't think it will present much of a maintenance burden.

@bors r+

@cuviper
Copy link
Member Author

cuviper commented Mar 2, 2023

Wrong bot...

bors r+

@bors bors bot merged commit 322dfe8 into rayon-rs:master Mar 2, 2023
@cuviper cuviper deleted the yield branch June 22, 2023 17:54
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

Successfully merging this pull request may close these issues.

pre-RFC: rayon::yield_now
2 participants