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

Get the global thread pool repeatedly (to pass to a function) #909

Open
kno10 opened this issue Jan 7, 2022 · 6 comments
Open

Get the global thread pool repeatedly (to pass to a function) #909

kno10 opened this issue Jan 7, 2022 · 6 comments

Comments

@kno10
Copy link

kno10 commented Jan 7, 2022

Assume I am writing a library with a function

fn lots_of_work(&pool: ThreadPool) {
  pool.scope(|s| { s.spawn( ... ); })
}

where the responsibility of configuring and selecting the thread pool is delegated to the caller.

The user can use the global thread pool via

let pool = rayon::ThreadPoolBuilder::new().build_global().unwrap();
lots_of_work(&pool)

but this can only be called once, because build_global() fails if used a second time.

But I do not want the user to have to create a new thread pool every time, either.

What is the best way to allow the user to call the function with the default thread pool?
I could not find something like

lots_of_work(rayon::get_global_threadpool())

where the user does not need to track his reference to the global pool forever.

@cuviper
Copy link
Member

cuviper commented Jan 7, 2022

The user can use the global thread pool via

let pool = rayon::ThreadPoolBuilder::new().build_global().unwrap();
lots_of_work(&pool)

This doesn't work even once, because build_global() doesn't give you a pool handle at all.

One thing you can do right now is make the pool argument optional:

fn lots_of_work(pool: Option<&ThreadPool>) {
    if let Some(pool) = opt_pool {
        pool.scope(|s| do_scoped_work(s))
    } else {
        rayon::scope(|s| do_scoped_work(s))
    }
}

However, a caveat is that rayon::scope will use the current pool, which may not be the global pool if you're already running in a pool thread. That might be a useful semantic for you anyway, but there's not currently a way to force use of the actual global pool from any arbitrary context.

See also #841 proposing to expose the current pool handle, and we could possibly do similar for the explicit global pool.

@kno10
Copy link
Author

kno10 commented Jan 7, 2022

Does this mean that if the user did

pool.scope(|s| do_scoped_work())

fn do_scoped_work() {
  rayon::scope(|s| ...)
}

then rayon::scope would use the pool configured before and not the global pool? That would be fine, as there is no need to switch between multiple pools in my code.

@cuviper
Copy link
Member

cuviper commented Jan 7, 2022

Correct, rayon::scope will use whatever pool you're currently in, or else the global pool as a fallback.

@cuviper
Copy link
Member

cuviper commented Jan 7, 2022

The user can also call pool.install(|| do_scoped_work()) to avoid the extra scope machinery.

@kno10
Copy link
Author

kno10 commented Jan 7, 2022

Maybe this could be clarified in the documentation.
E.g., the documentation of rayon::spawn says "Fires off a task into the Rayon threadpool in the “static” or “global” scope."
I assume this also rather uses the thread's current scope then, and not the global scope (unless there is no more local scope)?

@cuviper
Copy link
Member

cuviper commented Jan 7, 2022

Hmm, I think the point rayon::spawn is trying to make is more about how that runs detached in the pool, compared to Scope::spawn that is still detached but bounded by the scope. It's not really talking about which pool there, but it should probably avoid the word "global". (It might have predated support for non-global pools in the first place.)

Documentation improvements are always welcome!

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