rustasync / runtime

Empowering everyone to build asynchronous software
https://docs.rs/runtime
Apache License 2.0
862 stars 28 forks source link

Add API for explicitly starting/stopping runtimes and spawning futures on a specific runtime #42

Closed sdroege closed 4 years ago

sdroege commented 5 years ago

Currently runtimes in runtime are fully implicit and run in the background without any control over their lifetime, what futures get run on them or what (and how many threads) they use.

It would be useful to have API for all of the above. There are a couple of use-cases I can think of, some of which I'm doing with tokio currently in one way or another.

  1. Usage of runtimes in library crates without interfering with any other futures code other library crates or the application might use. This would potentially also go with specific per-thread configuration inside the library crate, for e.g. setting thread priorities of the runtime in a way that is meaningful for what this specific library is doing. See also https://github.com/rustasync/runtime/issues/8
  2. Similar to the above, but an extension: plugins. For plugins you might want to use a runtime internally, but at some point you might want to be able to unload the plugin again. Doing so requires to be able to shut down the runtime at a specific point and to ensure that none of the code of the plugin is running anymore.
  3. Error isolation. While this is probably done even better with separate processes, being able to compartmentalize the application into different parts that don't implicitly share any memory with each other could be useful, also for debuggability.
  4. Integration with other runtimes, like the GLib one (see also https://github.com/rustasync/runtime/issues/21#issuecomment-492608914). There you can (and generally do in bigger applications) create and run multiple runtimes (GMainContext / GMainLoop). There's the global default one, which is used also for the GTK+ toolkit to do all the UI things, but if you have other parts of your application doing async operations it often makes sense to create a separate one that runs on another thread (they're always single-threaded) to not interfere with the UI event loop in any way.

I realize that this goes a bit against the goal of making everything as simple as possible to use, but maybe such an API for starting/stopping/configuring runtimes could be made available in addition to the simple, do-it-all-implicitly API.

yoshuawuyts commented 5 years ago

I wonder if we follow #43, we could in addition also add a builder to set varying options. Not quite sure what that API would look like, but I think it might allow us to tick the right boxes (:

sdroege commented 5 years ago

43 is mostly about being able to call async functions in a blocking fashion, or not? While that might internally spawn a runtime (or maybe just run things on an existing runtime and block on a condition variable?), this seems not that closely related to being able to spawn and shut down your own runtimes in one way or another.

For that you probably don't necessarily want to block directly on a future but have some more API for a) creating a runtime (with whatever settings), b) actually starting it (which for a single threaded runtime would block the current thread, otherwise probably not?), and c) for shutting it down (and being able to wait for it to be shut down). I realize that you model a) and b) together with such a block_on() API, and have c) simply be a way to finish the given future (e.g. via a oneshot channel), but the mixing of the aspects of block_on and "start/create a new runtime" seems a bit unclean to me.

But maybe you're thinking of a nice API for doing all that together at once that I don't see right now, so maybe it's actually fine :)

yoshuawuyts commented 5 years ago

@sdroege thanks for clarifying! -- I think I might have intially missed some of the constraints you laid out, so this has been very helpful!