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 a LocalRuntime for replacing Runtime+LocalSet #6739

Open
Darksonn opened this issue Aug 1, 2024 · 4 comments
Open

Add a LocalRuntime for replacing Runtime+LocalSet #6739

Darksonn opened this issue Aug 1, 2024 · 4 comments
Assignees
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-runtime Module: tokio/runtime

Comments

@Darksonn
Copy link
Contributor

Darksonn commented Aug 1, 2024

Currently, to spawn !Send tasks on Tokio you must use a combination of a current-thread runtime and LocalSet to make that work. However, tasks on a LocalSet are separate from the rest of the runtime in an uncomfortable way. For example:

  • Tasks on the LocalSet can tokio::spawn to get onto the runtime, but once you're on the runtime, you can no longer spawn_local to get back into the LocalSet.
  • From the runtime's perspective, all of the tasks in the LocalSet behave like a single task using FuturesUnordered, so various runtime options such as event_interval behave in a very surprising way by counting many tasks at once.
  • After discussions with Deno, the LocalSet has been shown to involve considerable performance overhead compared to unsafely spawning the !Send tasks onto a current-thread runtime.

For the above reasons, I propose introducing a new type called LocalRuntime which behaves exactly like a current-thread Runtime with the following exceptions:

  • The LocalRuntime type is !Send to enable spawning !Send tasks directly onto the runtime.
  • From within a LocalRuntime, the tokio::spawn and spawn_local functions have identical behavior.
  • Tasks spawned using spawn_local are scheduled in the same way as normal tokio::spawn tasks.

Since Runtime and LocalSet share a fair amount of their internals, the implementation of current-thread should not require changes to support this.

@Darksonn Darksonn added A-tokio Area: The main tokio crate M-runtime Module: tokio/runtime C-feature-request Category: A feature request. labels Aug 1, 2024
@Noah-Kennedy
Copy link
Contributor

I am strongly in favor of this proposal, and would be happy to take some time and write a PR to add this to tokio_unstable.

Noah-Kennedy added a commit that referenced this issue Aug 30, 2024
This change adds LocalRuntime, a new unstable runtime type which cannot be transferred across thread boundaries and supports spawn_local when called from the thread which owns the runtime.

The initial set of docs for this are iffy. Documentation is absent right now at the module level, with the docs for the LocalRuntime struct itself being somewhat duplicative of those for the `Runtime` type. This can probably be addressed later as stabilization nears.

This API has a few interesting implementation details:
- because it was considered beneficial to reuse the same Handle as the normal runtime, it is possible to call spawn_local from a runtime context while on a different thread from the one which drives the runtime and owns it. This forces us to check the thread ID before attempting a local spawn.
- An empty LocalOptions struct is passed into the build_local method in order to build the runtime. This will eventually have stuff in it like hooks.

Relates to #6739.
@Noah-Kennedy Noah-Kennedy self-assigned this Aug 30, 2024
@Noah-Kennedy
Copy link
Contributor

I've opened a PR to add this as an unstable API: #6808

@carllerche
Copy link
Member

Generally, I agree with the reasoning for adding LocalSet. We would need to think about how to position this with the current thread runtime. Both LocalRuntime and CurrentThreadRuntime have a lot of overlap. So, how to pick each one would need to be clear.

@Noah-Kennedy
Copy link
Contributor

Generally, I agree with the reasoning for adding LocalSet. We would need to think about how to position this with the current thread runtime. Both LocalRuntime and CurrentThreadRuntime have a lot of overlap. So, how to pick each one would need to be clear.

I think the decision tree here comes down to several things:

  • do you want to be able to seamlessly switch between multi_thread and current_thread (e.g via a config file entry in your service)
  • do you want to move runtimes between threads (not as dumb as it sounds)
  • do you actually care about spawn_local

Noah-Kennedy added a commit that referenced this issue Oct 2, 2024
This change adds LocalRuntime, a new unstable runtime type which cannot be transferred across thread boundaries and supports spawn_local when called from the thread which owns the runtime.

The initial set of docs for this are iffy. Documentation is absent right now at the module level, with the docs for the LocalRuntime struct itself being somewhat duplicative of those for the `Runtime` type. This can probably be addressed later as stabilization nears.

This API has a few interesting implementation details:
- because it was considered beneficial to reuse the same Handle as the normal runtime, it is possible to call spawn_local from a runtime context while on a different thread from the one which drives the runtime and owns it. This forces us to check the thread ID before attempting a local spawn.
- An empty LocalOptions struct is passed into the build_local method in order to build the runtime. This will eventually have stuff in it like hooks.

Relates to #6739.
Noah-Kennedy added a commit that referenced this issue Oct 12, 2024
This change adds LocalRuntime, a new unstable runtime type which cannot be transferred across thread boundaries and supports spawn_local when called from the thread which owns the runtime.

The initial set of docs for this are iffy. Documentation is absent right now at the module level, with the docs for the LocalRuntime struct itself being somewhat duplicative of those for the `Runtime` type. This can probably be addressed later as stabilization nears.

This API has a few interesting implementation details:
- because it was considered beneficial to reuse the same Handle as the normal runtime, it is possible to call spawn_local from a runtime context while on a different thread from the one which drives the runtime and owns it. This forces us to check the thread ID before attempting a local spawn.
- An empty LocalOptions struct is passed into the build_local method in order to build the runtime. This will eventually have stuff in it like hooks.

Relates to #6739.
Noah-Kennedy added a commit that referenced this issue Oct 12, 2024
This change adds LocalRuntime, a new unstable runtime type which cannot be transferred across thread boundaries and supports spawn_local when called from the thread which owns the runtime.

The initial set of docs for this are iffy. Documentation is absent right now at the module level, with the docs for the LocalRuntime struct itself being somewhat duplicative of those for the `Runtime` type. This can be addressed later as stabilization nears.

This API has a few interesting implementation details:
- because it was considered beneficial to reuse the same Handle as the normal runtime, it is possible to call spawn_local from a runtime context while on a different thread from the one which drives the runtime and owns it. This forces us to check the thread ID before attempting a local spawn.
- An empty LocalOptions struct is passed into the build_local method in order to build the runtime. This will eventually have stuff in it like hooks.

Relates to #6739.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tokio Area: The main tokio crate C-feature-request Category: A feature request. M-runtime Module: tokio/runtime
Projects
None yet
Development

No branches or pull requests

3 participants