Simplifying Task Spawning in Tokio with LocalRuntime
Core Problem
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.
Solution & Analysis
use tokio::runtime::{Builder, CurrentThread};
// Introduce LocalRuntime type that behaves like a current-thread Runtime
pub struct LocalRuntime;
impl LocalRuntime {
fn new() -> Self {
// Create a new builder for a current-thread runtime
let mut builder = Builder::new_multi_thread();
// Set the local set to be the same as the current thread's local set
builder.local_set();
// Return the created runtime
builder.build_current_thread().unwrap()
}
}
impl Runtime for LocalRuntime {
type Future = ();
fn spawn<F: FnOnce() + Send>(&self, fut: F) -> Pin<Box<dyn Future<Self::Future> + 'static>> {
Box::pin(self.current_thread().spawn(fut))
}
fn spawn_local<F: FnOnce() + Unpin>(&self, fut: F) -> Pin<Box<dyn Future<Self::Future> + Send + Unpin>> {
// Since LocalRuntime is !Send, we can use tokio::spawn directly
Box::pin(self.current_thread().spawn(fut))
}
}
Conclusion
The LocalRuntime type simplifies task spawning in Tokio by providing a more comfortable and efficient way to spawn !Send tasks. With this introduction, developers can easily spawn tasks on the local thread without relying on LocalSet.