Search code examples
multithreadingrustasync-awaitrust-tokio

How to run async tasks in several threads in Rust


I want to run some async tasks in several threads. I tried to use tokio's Runtime and new_multi_thread, but I've got a panic

thread 'main' panicked at 'Cannot drop a runtime in a context where blocking is not allowed. This happens when a runtime is dropped from within an asynchronous context.'

Here's the code.

async fn routine(millis: u64) {
    tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
}

#[tokio::main]
async fn main() {
    let rt = tokio::runtime::Builder::new_multi_thread().worker_threads(2).enable_all().build().unwrap();

    let handles: Vec<tokio::task::JoinHandle<_>> = (1..10_u64).map(|i| {
        rt.spawn(routine(i))
    }).collect();

    for handle in handles {
        handle.await.unwrap();
    }
}

Could you please tell me what is wrong with the code?


Solution

  • You don't need to initialize a runtime as that's what the annotation #[tokio::main] does (it's a macro).

    This...

    #[tokio::main]
    async fn main() {
        println!("hello");
    }
    

    ...de-sugars to:

    fn main() {
        tokio::runtime::Builder::new_multi_thread()
            .enable_all()
            .build()
            .unwrap()
            .block_on(async {
                println!("hello");
            })
    }
    

    Note that #[tokio::main] is equivalent to #[tokio::main(flavor = "multi_thread")] (defaults to multi-threaded runtime), as opposed to the single-threaded runtime #[tokio::main(flavor = "current_thread")]. In your case you can use this form #[tokio::main(worker_threads = 2)].