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?
CodePudding user response:
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)].
CodePudding user response:
#[tokio::main] creates a Runtime and runs async fn main() on it. Your main then creates another Runtime. Normally, when we create our own runtime, we wouldn't use the #[tokio::main] macro, we'd just write a normal main.
We can use block_on to wait for the tasks to complete, then we can drop the Runtime. With a normal main, we're not dropping the Runtime in an asynchronous context, so the program no longer panics.
async fn routine(millis: u64) {
println!("in routine({millis})");
tokio::time::sleep(std::time::Duration::from_millis(millis)).await;
}
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();
rt.block_on(async {
for handle in handles {
handle.await.unwrap();
}
});
}
