当前位置:首页 > 科技  > 软件

Rust Tokio取消任务的几种模式,你知道吗?

来源: 责编: 时间:2024-05-20 17:53:30 222观看
导读Rust提供了对异步编程的支持,它可以生成异步任务,然后通过运行时执行器在操作系统线程之间调度执行。与Rust中的所有东西一样,异步编程必须是内存安全的,因此需要确保借用检查器可以编译通过。这篇文章是关于任务取消模式

Rust提供了对异步编程的支持,它可以生成异步任务,然后通过运行时执行器在操作系统线程之间调度执行。4cG28资讯网——每日最新资讯28at.com

与Rust中的所有东西一样,异步编程必须是内存安全的,因此需要确保借用检查器可以编译通过。4cG28资讯网——每日最新资讯28at.com

这篇文章是关于任务取消模式的,下面我们来介绍Tokio任务的取消模式。4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

Select 和 Channels

所有这些模式的核心是两个tokio特性:4cG28资讯网——每日最新资讯28at.com

  • channel:用于任务间通信
  • select:用于等待多个异步计算(不一定是任务!)

Tokio channel看起来有点复杂,但同时就程序的内存安全和弹性而言,它很强大。Tokio channel创建了两个不同的对象,用于任务之间的通信,不能同时使用一个通道对象来接收和发送。4cG28资讯网——每日最新资讯28at.com

Tokio提供的频道实际上有四种:4cG28资讯网——每日最新资讯28at.com

  • mpsc:多个生产者,单一消费者
  • oneshot:用于发送和接收单个值,发送后,通道关闭。
  • broadcast:多个发送者,多个消费者
  • watch:单一生产者,多个消费者

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

Drop JoinHandle不会取消任务

JoinHandle在删除关联的任务时将其分离,这意味着不再有任何任务句柄,也没有办法对其进行连接。4cG28资讯网——每日最新资讯28at.com

每次在tokio中生成任务时,都会返回JoinHandle。可以使用join句柄来等待任务完成,但是认为可以使用它来简单地通过删除任务来强制终止任务是错误的。这里有一个愚蠢的例子:4cG28资讯网——每日最新资讯28at.com

use tokio::time::{self, Duration};#[tokio::main]async fn main() {    let handle = tokio::spawn(async {        // do some work        tokio::time::sleep(Duration::from_secs(10)).await;        println!("Task completed");    });    // 100毫秒后取消任务    time::sleep(Duration::from_millis(100)).await;    drop(handle);    println!("Task was cancelled");}

4cG28资讯网——每日最新资讯28at.com

丢弃句柄并不会取消正在运行的任务!4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

Abort任务

这是取消任务的最极端的方式,没有清理的空间:4cG28资讯网——每日最新资讯28at.com

use tokio::time::{self, Duration};#[tokio::main]async fn main() {    let handle = tokio::spawn(async {        // do some work        tokio::time::sleep(Duration::from_secs(1)).await;        println!("Task completed");    });    // 100毫秒后取消任务    time::sleep(Duration::from_millis(100)).await;    handle.abort();    time::sleep(Duration::from_secs(2)).await;    println!("Task was cancelled");}

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

使用oneshot channel

oneshot channel允许通道上的发送单个值,可以由多个接收器侦听。与drop模式不同,此模式允许通道执行一些清理工作。这里有一个例子:4cG28资讯网——每日最新资讯28at.com

use tokio::sync::oneshot;use tokio::time::Duration;#[tokio::main]async fn main() {    let (tx, rx) = oneshot::channel();    let task = tokio::spawn(async move {        tokio::select! {            _ = rx => {                println!("Task is cancelling...");            }            _ = tokio::time::sleep(Duration::from_secs(10)) => {                println!("Task completed normally");            }        }        println!("Task is cleaning up");    });    tokio::time::sleep(Duration::from_millis(100)).await;    // 发送取消信号    let _ = tx.send(());    // 等待任务完成    let _ = task.await;}

4cG28资讯网——每日最新资讯28at.com

运行结果如下:4cG28资讯网——每日最新资讯28at.com

Task is cancelling...Task is cleaning up

4cG28资讯网——每日最新资讯28at.com

oneshot channel的限制是你不能用它来取消多个任务。4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

使用broadcast channel取消多个任务

如果要取消多个任务,可以使用broad channel。可以有多个生产者向通道发送信息,也可以有多个消费者从通道接收信息。每个接收方都可以看到在通道上发送的每个值。4cG28资讯网——每日最新资讯28at.com

这里有一个简单的例子,来演示如何使用它来取消多个任务:4cG28资讯网——每日最新资讯28at.com

use tokio::sync::broadcast;use tokio::time::Duration;#[tokio::main]async fn main() {    let (tx, mut rx1) = broadcast::channel(1);    let mut rx2 = tx.subscribe();    let task1 = tokio::spawn(async move {        tokio::select! {            _ = rx1.recv() => {                println!("Task 1 is cancelling...");            }            _ = tokio::time::sleep(Duration::from_secs(10)) => {                println!("Task 1 completed normally");            }        }        println!("Task 1 is cleaning up");    });    let task2 = tokio::spawn(async move {        tokio::select! {            _ = rx2.recv() => {                println!("Task 2 is cancelling...");            }            _ = tokio::time::sleep(Duration::from_secs(10)) => {                println!("Task 2 completed normally");            }        }        println!("Task 2 is cleaning up");    });    tokio::time::sleep(Duration::from_millis(100)).await;    // 发送取消信号    let _ = tx.send(());    // 等待任务完成    let _ = tokio::join!(task1, task2);}

4cG28资讯网——每日最新资讯28at.com

运行结果如下:4cG28资讯网——每日最新资讯28at.com

Task 2 is cancelling...Task 2 is cleaning upTask 1 is cancelling...Task 1 is cleaning up

取消的顺序可能会有所不同,因为任务可能会以不同的顺序取消!4cG28资讯网——每日最新资讯28at.com

如果只想从单个任务向多个任务发送取消信号,那么broad channel可能有点过度,因为它提供了在多个任务之间传递消息的所有机制。4cG28资讯网——每日最新资讯28at.com

如果既需要消息传递又需要消息取消,这很方便。但如果只需要消息取消,还有更好的方法,开销更少:watch channel。4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

使用watch channel取消多个任务

watch channel是多个消费者频道的单一生产者。watch channel给了任务清理自己的机会。缺点是,消费者只能看到通道上发送的最近的值——这意味着如果任务在通道上发送了一个值之后启动,它可能会错过它,因此不会被取消,所以要小心这一点。这里有一个简单的例子:4cG28资讯网——每日最新资讯28at.com

use tokio::sync::watch;use tokio::time::Duration;#[tokio::main]async fn main() {    let (tx, mut rx1) = watch::channel(false);    let mut rx2 = tx.subscribe();    let task1 = tokio::spawn(async move {        loop {            tokio::select! {                _ = rx1.changed() => {                    if *rx1.borrow() {                        println!("Task 1 is cancelling...");                        break;                    }                }                _ = tokio::time::sleep(Duration::from_secs(10)) => {                    println!("Task 1 completed normally");                    break;                }            }        }        println!("Task 1 is cleaning up");    });    let task2 = tokio::spawn(async move {        loop {            tokio::select! {                _ = rx2.changed() => {                    if *rx2.borrow() {                        println!("Task 2 is cancelling...");                        break;                    }                }                _ = tokio::time::sleep(Duration::from_secs(10)) => {                    println!("Task 2 completed normally");                    break;                }            }        }        println!("Task 2 is cleaning up");    });    tokio::time::sleep(Duration::from_millis(100)).await;    // 发送取消信号    let _ = tx.send(true);    // 等待任务完成    let _ = tokio::join!(task1, task2);}

4cG28资讯网——每日最新资讯28at.com

4cG28资讯网——每日最新资讯28at.com

取消令牌

官方的Tokio文档中列出了一种名为CancellationToken的东西,用于优雅关机。这在tokio crate本身中不可用,但在相关的toko_util crate中可用。4cG28资讯网——每日最新资讯28at.com

use tokio::time::{sleep, Duration};use tokio_util::sync::CancellationToken;#[tokio::main]async fn main() {    // Create a CancellationToken    let token = CancellationToken::new();    let token1 = token.clone();    let token2 = token.clone();    let task1 = tokio::spawn(async move {        loop {            tokio::select! {                _ = token1.cancelled() => {                        println!("Task 1 is cancelling...");                        break;                }                _ = tokio::time::sleep(Duration::from_secs(10)) => {                    println!("Task 1 completed normally");                    break;                }            }        }        println!("Task 1 is cleaning up");    });    let task2 = tokio::spawn(async move {        loop {            tokio::select! {                _ = token2.cancelled() => {                        println!("Task 2 is cancelling...");                        break;                }                _ = tokio::time::sleep(Duration::from_secs(10)) => {                    println!("Task 2 completed normally");                    break;                }            }        }        println!("Task 2 is cleaning up");    });    sleep(Duration::from_millis(100)).await;    // 发送取消信号    token.cancel();    // 等待任务完成    let _ = tokio::join!(task1, task2);}

请注意我们是如何克隆令牌的,以便将其移动到各个异步任务中。4cG28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-89399-0.htmlRust Tokio取消任务的几种模式,你知道吗?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 基于Jenkins Pipeline构建企业级CI/CD

下一篇: 小米面试:如何实现优先级线程池?

标签:
  • 热门焦点
  • 跑分安卓第一!Redmi K60至尊版8月发布!卢伟冰:目标年度性能之王

    8月5日消息,Redmi K60至尊版将于8月发布,在此前举行的战略发布会上,官方该机将搭载搭载天玑9200+处理器,安兔兔V10跑分超177万分,是目前安卓阵营最高的分数
  • Raft算法:保障分布式系统共识的稳健之道

    1. 什么是Raft算法?Raft 是英文”Reliable、Replicated、Redundant、And Fault-Tolerant”(“可靠、可复制、可冗余、可容错”)的首字母缩写。Raft算法是一种用于在分布式系统
  • 线程通讯的三种方法!通俗易懂

    线程通信是指多个线程之间通过某种机制进行协调和交互,例如,线程等待和通知机制就是线程通讯的主要手段之一。 在 Java 中,线程等待和通知的实现手段有以下几种方式:Object 类下
  • 2023 年的 Node.js 生态系统

    随着技术的不断演进和创新,Node.js 在 2023 年达到了一个新的高度。Node.js 拥有一个庞大的生态系统,可以帮助开发人员更快地实现复杂的应用。本文就来看看 Node.js 最新的生
  • 深度探索 Elasticsearch 8.X:function_score 参数解读与实战案例分析

    在 Elasticsearch 中,function_score 可以让我们在查询的同时对搜索结果进行自定义评分。function_score 提供了一系列的参数和函数让我们可以根据需求灵活地进行设置。近期
  • 三万字盘点 Spring 九大核心基础功能

    大家好,我是三友~~今天来跟大家聊一聊Spring的9大核心基础功能。话不多说,先上目录:图片友情提示,本文过长,建议收藏,嘿嘿嘿!一、资源管理资源管理是Spring的一个核心的基础功能,不
  • 2023年,我眼中的字节跳动

    此时此刻(2023年7月),字节跳动从未上市,也从未公布过任何官方的上市计划;但是这并不妨碍它成为中国最受关注的互联网公司之一。从2016-17年的抖音强势崛起,到2018年的“头腾
  • 3699元!iQOO Neo8 Pro顶配版今日首销:1TB UFS 4.0同价位唯一

    5月23日,iQOO推出了全新的iQOO Neo8系列,包含iQOO Neo8和iQOO Neo8 Pro两个版本,其中标准版搭载高通骁龙8+,而Pro版更是首发搭载了联发科天玑9200+旗舰
  • 2022爆款:ROG魔霸6 冰川散热系统持续护航

    喜逢开学季,各大商家开始推出自己的新产品,进行打折促销活动。对于忠实的端游爱好者来说,能够拥有一款梦寐以求的笔记本电脑是一件十分开心的事。但是现在的
Top