I'm trying to create a second threaded runtime to act as a replacement of futures-cpupool (because reasons).
This code:
fn main() {
let mut main_runtime = tokio::runtime::Runtime::new().unwrap();
let cpu_pool = tokio::runtime::Builder::new().threaded_scheduler().build().unwrap();
// let cpu_pool = cpu_pool.handle().clone();
main_runtime.block_on(main_runtime.spawn(async move {
cpu_pool.spawn(async {}).await
}))
.unwrap().unwrap();
}
Fails with:
thread 'tokio-runtime-worker' panicked at 'Cannot start a runtime from within a runtime. This happens because a function (like
block_on) attempted to block the current thread while the thread is being used to drive asynchronous tasks.'
I don't think I'm violating any rules here: both runtimes are created outside of a runtime, and only one of them runs block_on.
On top of that, using Handle for spawn instead of the runtime directly, makes it work:
fn main() {
let mut main_runtime = tokio::runtime::Runtime::new().unwrap();
let cpu_pool = tokio::runtime::Builder::new().threaded_scheduler().build().unwrap();
let cpu_pool = cpu_pool.handle().clone();
main_runtime.block_on(main_runtime.spawn(async move {
cpu_pool.spawn(async {}).await
}))
.unwrap().unwrap();
}
Is this the expected behavior?
Thank you for the bug report. This definitely seems like a bug. Note that this simplified version also panics:
use tokio::runtime::Builder;
fn main() {
let mut rt = Builder::new().threaded_scheduler().build().unwrap();
let matching_rt = Builder::new().threaded_scheduler().build().unwrap();
let handle = matching_rt.handle().clone();
rt.block_on(async move {
handle.spawn(async {}).await
}).unwrap();
}
Thank you for the bug report. This definitely seems like a bug. Note that this simplified version also panics:
use tokio::runtime::Builder; fn main() { let mut rt = Builder::new().threaded_scheduler().build().unwrap(); let matching_rt = Builder::new().threaded_scheduler().build().unwrap(); let handle = matching_rt.handle().clone(); rt.block_on(async move { handle.spawn(async {}).await }).unwrap(); }
this example do not panic, but if you replace handle.spawn with matching_rt.spawn it will panic.
@cssivision Oops, that's what I meant!
rt.block_on(async move {
matching_rt.spawn(async {}).await
}).unwrap();
The problem here is async move: matching_rt is moved into the blocking task, and is dropped at the end. When matching_rt is dropped, it blocks to shut down all pending tasks.
Changing async move to async is enough to fix this example.
Relevant parts of the stack trace:
11: std::panicking::begin_panic
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/panicking.rs:397
12: tokio::runtime::enter::enter
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/enter.rs:38
13: tokio::runtime::blocking::shutdown::Receiver::wait
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/blocking/shutdown.rs:44
14: tokio::runtime::blocking::pool::BlockingPool::shutdown
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/blocking/pool.rs:132
15: <tokio::runtime::blocking::pool::BlockingPool as core::ops::drop::Drop>::drop
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/blocking/pool.rs:138
16: core::ptr::drop_in_place
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libcore/ptr/mod.rs:177
17: core::ptr::drop_in_place
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libcore/ptr/mod.rs:177
18: playground::main::{{closure}}
at src/main.rs:11
19: <std::future::GenFuture<T> as core::future::future::Future>::poll
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/future.rs:44
20: tokio::runtime::enter::Enter::block_on::{{closure}}
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/enter.rs:163
21: tokio::coop::budget::{{closure}}
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/coop.rs:97
22: std::thread::local::LocalKey<T>::try_with
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:262
23: std::thread::local::LocalKey<T>::with
at /rustc/8d69840ab92ea7f4d323420088dd8c9775f180cd/src/libstd/thread/local.rs:239
24: tokio::coop::budget
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/coop.rs:79
25: tokio::runtime::enter::Enter::block_on
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/enter.rs:163
26: tokio::runtime::thread_pool::ThreadPool::block_on
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/thread_pool/mod.rs:82
27: tokio::runtime::Runtime::block_on::{{closure}}
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/mod.rs:446
28: tokio::runtime::context::enter
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/context.rs:72
29: tokio::runtime::handle::Handle::enter
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/handle.rs:71
30: tokio::runtime::Runtime::block_on
at ./.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-0.2.20/src/runtime/mod.rs:441
31: playground::main
at src/main.rs:9
@jebrosen Thanks for the diagnosis.
Would it be possible to improve this error message to specifically mention it's coming from Tokio's own destructor? Destructors are invisible and I wouldn't have guessed it's about that, and not my spawn call.
I suppose that would be possible to do. These panic messages need improvement in any case, but this sounds like a reasonable idea.
is this issue resolved ?
Yes, the panic message was fixed in #2646.
Most helpful comment
The problem here is
async move:matching_rtis moved into the blocking task, and isdropped at the end. Whenmatching_rtis dropped, it blocks to shut down all pending tasks.Changing
async movetoasyncis enough to fix this example.Relevant parts of the stack trace: