为什么调用 tokio::spawn 会导致恐慌 "SpawnError { is_shutdown: true }"?
Why does calling tokio::spawn result in the panic "SpawnError { is_shutdown: true }"?
我想用 Delay
做一些工作。如果我使用 tokio::run
,它工作正常,但在使用 tokio::spawn
:
时它会崩溃
use std::sync::mpsc;
use std::time::*;
use tokio::prelude::*; // 0.1.14
fn main() {
let (tx, rx) = mpsc::channel();
let task = tokio::timer::Delay::new(Instant::now() + Duration::from_secs(1))
.map(move |_| {
tx.send(String::from("hello")).unwrap();
()
})
.map_err(|e| {
panic!("{:?}", e);
});
tokio::spawn(task);
let msg = rx.recv().unwrap();
println!("{}", msg);
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SpawnError { is_shutdown: true }', src/libcore/result.rs:1009:5
如果我希望多个任务同时工作,我需要使用 spawn
而不是 run
。如何更改代码以使其工作?
tokio::spawn
的文档指出:
This function will panic if the default executor is not set or if spawning onto the default executor returns an error.
实际上,这意味着 tokio::spawn
只能从 内部调用 对 tokio::run
.
的调用
因为你只有一个未来要执行,你不妨直接将它传递给 tokio::run
。如果您有多个期货,那么您可以利用 future::lazy
构建一个延迟计算的期货,它将在最终运行时调用 spawn
:
use std::time::*;
use tokio::prelude::*; // 0.1.14
fn main() {
tokio::run(futures::lazy(|| {
tokio::spawn(wait_one_sec().map(|_| println!("One")));
tokio::spawn(wait_one_sec().map(|_| println!("Two")));
Ok(())
}));
}
fn wait_one_sec() -> impl Future<Item = (), Error = ()> {
tokio::timer::Delay::new(Instant::now() + Duration::from_secs(1))
.map(drop)
.map_err(|e| panic!("{:?}", e))
}
请注意,如果您忘记了 futures::lazy
,则会出现相同的错误。这是因为函数的参数是急切求值的,这意味着对 tokio::spawn
的调用首先发生,导致相同的事件序列。
use std::sync::mpsc;
我认为您是否想使用标准库通道非常值得怀疑,因为它们不支持异步,因此会阻塞 — 这在异步代码中是一件非常糟糕的事情。
相反,您可能需要 futures::sync::mpsc
。
我想用 Delay
做一些工作。如果我使用 tokio::run
,它工作正常,但在使用 tokio::spawn
:
use std::sync::mpsc;
use std::time::*;
use tokio::prelude::*; // 0.1.14
fn main() {
let (tx, rx) = mpsc::channel();
let task = tokio::timer::Delay::new(Instant::now() + Duration::from_secs(1))
.map(move |_| {
tx.send(String::from("hello")).unwrap();
()
})
.map_err(|e| {
panic!("{:?}", e);
});
tokio::spawn(task);
let msg = rx.recv().unwrap();
println!("{}", msg);
}
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SpawnError { is_shutdown: true }', src/libcore/result.rs:1009:5
如果我希望多个任务同时工作,我需要使用 spawn
而不是 run
。如何更改代码以使其工作?
tokio::spawn
的文档指出:
This function will panic if the default executor is not set or if spawning onto the default executor returns an error.
实际上,这意味着 tokio::spawn
只能从 内部调用 对 tokio::run
.
因为你只有一个未来要执行,你不妨直接将它传递给 tokio::run
。如果您有多个期货,那么您可以利用 future::lazy
构建一个延迟计算的期货,它将在最终运行时调用 spawn
:
use std::time::*;
use tokio::prelude::*; // 0.1.14
fn main() {
tokio::run(futures::lazy(|| {
tokio::spawn(wait_one_sec().map(|_| println!("One")));
tokio::spawn(wait_one_sec().map(|_| println!("Two")));
Ok(())
}));
}
fn wait_one_sec() -> impl Future<Item = (), Error = ()> {
tokio::timer::Delay::new(Instant::now() + Duration::from_secs(1))
.map(drop)
.map_err(|e| panic!("{:?}", e))
}
请注意,如果您忘记了 futures::lazy
,则会出现相同的错误。这是因为函数的参数是急切求值的,这意味着对 tokio::spawn
的调用首先发生,导致相同的事件序列。
use std::sync::mpsc;
我认为您是否想使用标准库通道非常值得怀疑,因为它们不支持异步,因此会阻塞 — 这在异步代码中是一件非常糟糕的事情。
相反,您可能需要 futures::sync::mpsc
。