Может ли задача Tokio завершить все время выполнения изящно? - PullRequest
0 голосов
/ 04 февраля 2019

Я запускаю среду исполнения Tokio с кодом, подобным следующему:

tokio::run(my_future);

Мое будущее - запускать кучу задач в ответ на различные условия.

Одна из этих задач -ответственный за определение, когда программа должна закрыться.Однако я не знаю, как заставить эту задачу изящно завершить программу.В идеале, я хотел бы найти способ для этой задачи вызвать завершение вызова функции run.

Ниже приведен пример программы, которую я хотел бы написать:

extern crate tokio;

use tokio::prelude::*;

use std::time::Duration;
use std::time::Instant;

use tokio::timer::{Delay, Interval};

fn main() {
    let kill_future = Delay::new(Instant::now() + Duration::from_secs(3));

    let time_print_future = Interval::new_interval(Duration::from_secs(1));

    let mut runtime = tokio::runtime::Runtime::new().expect("failed to start new Runtime");
    runtime.spawn(time_print_future.for_each(|t| Ok(println!("{:?}", t))).map_err(|_| ()));
    runtime.spawn(
        kill_future
            .map_err(|_| {
                eprintln!("Timer error");
            })
            .map(move |()| {
                // TODO
                unimplemented!("Shutdown the runtime!");
            }),
    );
    // TODO
    unimplemented!("Block until the runtime is shutdown");
    println!("Done");
}

shutdown_now кажется многообещающим, но при дальнейшем исследовании, вероятно, не сработает.В частности, он берет на себя ответственность за среду выполнения, и Tokio, вероятно, не собирается разрешать, чтобы основной поток (где была создана среда выполнения) и какая-либо случайная задача владели средой выполнения.

1 Ответ

0 голосов
/ 05 февраля 2019

Вы можете использовать канал с одним выстрелом для связи изнутри среды выполнения и наружу.Когда задержка истекает, мы отправляем одно сообщение по каналу.

Вне времени выполнения, как только мы получаем это сообщение, мы инициируем завершение времени выполнения и wait для его завершения.

use std::time::{Duration, Instant};
use tokio::{
    prelude::*,
    runtime::Runtime,
    sync::oneshot,
    timer::{Delay, Interval},
}; // 0.1.15

fn main() {
    let mut runtime = Runtime::new().expect("failed to start new Runtime");

    let (tx, rx) = oneshot::channel();

    runtime.spawn({
        let every_second = Interval::new_interval(Duration::from_secs(1));
        every_second
            .for_each(|t| Ok(println!("{:?}", t)))
            .map_err(drop)
    });

    runtime.spawn({
        let in_three_seconds = Delay::new(Instant::now() + Duration::from_secs(3));
        in_three_seconds
            .map_err(|_| eprintln!("Timer error"))
            .and_then(move |_| tx.send(()))
    });

    rx.wait().expect("unable to wait for receiver");
    runtime
        .shutdown_now()
        .wait()
        .expect("unable to wait for shutdown");

    println!("Done");
}

См. Также:

...