Introducing LocalRuntime: Simplifying Task Spawning in Tokio
Core Problem
Currently, spawning !Send tasks on Tokio requires a combination of a current-thread runtime and LocalSet, leading to performance overhead and confusing behavior. This proposal introduces a new type called LocalRuntime, which simplifies task spawning while maintaining compatibility with the existing runtime.
Solution & Analysis
To address the issues with LocalSet, we introduce a new type LocalRuntime that behaves like a current-thread Runtime. The key differences are:
LocalRuntimeis!Send, enabling direct spawning of!Sendtasks onto the runtime.- Within a
LocalRuntime,tokio::spawnandspawn_localhave identical behavior, allowing for seamless task switching between normal and local tasks. - Tasks spawned using
spawn_localare scheduled similarly to normaltokio::spawntasks.
Here's an example implementation of the LocalRuntime type:
use tokio::runtime::{Builder, CurrentSchedExt};
use tokio::sync::oneshot;
use futures::channel::{oneshot as oneshot_channel,mpsc};
struct LocalRuntime {
// runtime fields...
}
impl LocalRuntime {
fn new() -> Self {
// create a new local runtime
todo!()
}
async fn spawn<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
// spawn the task on the local runtime
todo!()
}
async fn spawn_local<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
// spawn the task locally
todo!()
}
}
To use LocalRuntime, you can create a new instance and use its methods to spawn tasks:
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let local_runtime = LocalRuntime::new().await?;
// Spawn a task on the local runtime
local_runtime.spawn(async { println!("Task spawned locally") }).await?;
// Spawn a task using spawn_local
local_runtime.spawn_local(async { println!("Task spawned normally") }).await?;
Ok(())
}
Conclusion
The introduction of LocalRuntime simplifies task spawning in Tokio by providing a new, more efficient way to handle tasks that require direct access to the runtime. This change improves performance and reduces confusion around task behavior, making it easier for developers to write high-performance concurrent code with Tokio.