Why does calling tokio::spawn result in the panic “SpawnError { is_shutdown: true }”?

时间秒杀一切 提交于 2019-12-07 05:27:02

问题


I want to use Delay to do some work later. If I use tokio::run, it just works fine, but it panics when using 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

I need to use spawn not run if I want various tasks to work concurrently. How to change the code to make it work?


回答1:


The documentation for tokio::spawn states:

This function will panic if the default executor is not set or if spawning onto the default executor returns an error.

Effectively, this means that tokio::spawn should only be called from inside a call to tokio::run.

Since you have only a single future to execute, you might as well just pass it directly to tokio::run. If you had multiple futures, then you can make make use of future::lazy to construct a lazily-evaluated future that will call spawn when it eventually runs:

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))
}

Note that if you forget the futures::lazy then you will get the same error. This is because the arguments to functions are evaluated eagerly, which means that the call to tokio::spawn happens first, causing the same sequence of events.

use std::sync::mpsc;

I think it's highly doubtful that you want to use the standard libraries channels, as they are not async-aware and thus will block — a very bad thing in async code.

Instead, you probably want futures::sync::mpsc.



来源:https://stackoverflow.com/questions/54503625/why-does-calling-tokiospawn-result-in-the-panic-spawnerror-is-shutdown-tru

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!