【问题标题】:How to remotely shut down running tasks with Tokio如何使用 Tokio 远程关闭正在运行的任务
【发布时间】:2020-09-27 04:59:08
【问题描述】:

我有一个正在接收数据的 UDP 套接字

pub async fn start()  -> Result<(), std::io::Error> {
    loop {
        let mut data  = vec![0; 1024];
        socket.recv_from(&mut data).await?;
    }
}

当没有数据进入时,此代码当前在.await 上被阻止。我想从我的主线程优雅地关闭我的服务器,那么我如何向这个.await 发送信号,它应该停止睡觉然后关机?

【问题讨论】:

标签: rust rust-tokio


【解决方案1】:

注意:Tokio 网站在graceful shutdown 上有一个页面。

如果您要杀死多个任务,则应使用broadcast channel 发送关闭消息。可以和tokio::select!一起使用。

use tokio::sync::broadcast::Receiver;

// You may want to log errors rather than return them in this function.
pub async fn start(kill: Receiver<()>) -> Result<(), std::io::Error> {
    tokio::select! {
        output = real_start() => output,
        _ = kill.recv() => Err(...),
    }
}

pub async fn real_start() -> Result<(), std::io::Error> {
    loop {
        let mut data  = vec![0; 1024];
        socket.recv_from(&mut data).await?;
    }
}

然后要杀死所有任务,在频道上发送消息。


要只杀死单个任务,可以使用JoinHandle::abort 方法,它会尽快杀死任务。请注意,此方法仅在 Tokio 1.x 和 0.3.x 中可用,要使用 Tokio 0.2.x 中止任务,请参阅下面的下一节。

let task = tokio::spawn(start());

...

task.abort();

作为JoinHandle::abort 的替代品,您可以使用期货箱中的abortable。生成任务时,请执行以下操作:

let (task, handle) = abortable(start());
tokio::spawn(task);

然后你可以通过调用abort 方法终止任务。

handle.abort();

当然,带有select! 的频道也可以用于杀死单个任务,可能与oneshot 频道而不是广播频道结合使用。


所有这些方法都保证real_start 方法在.await 处被终止。在两个.awaits 之间运行代码时,无法终止该任务。你可以阅读更多关于为什么这是here

mini-redis 项目包含一个可访问的服务器正常关闭的真实示例。此外,Tokio 教程有关于 selectchannels 的章节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-13
    • 2015-06-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2020-07-30
    相关资源
    最近更新 更多