文盘Rust -- 用Tokio实现简易任务池

rust,tokio,实现,简易,任务 · 浏览次数 : 73

小编点评

**作者:京东科技 贾世闻Tokio 无疑是 Rust 世界中最优秀的异步Runtime实现。** **非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能。** **例子:** ```rust fn main(){ let max_task = 1; let rt = runtime::Builder::new_multi_thread() .worker_threads(max_task) .build() .unwrap(); rt.block_on(async { println!(\"tokio_multi_thread \"); for i in 0..100 { println!(\"run {}\", i); tokio::spawn(async move { println!(\"spawn {}\", i); thread::sleep(Duration::from_secs(2)); }); } }); } ``` **预期运行结构:** 通过异步任务打印出99个 “spawn i”,但实际输出的结果大概这样:`tokio_multi_threadrun 0run 1run 2.......run 16spawn 0run 17......run 99spawn 1spawn 2......spawn 29......spawn 58spawn 5959执行完后面就没有输出了,如果把max_task设置为2,情况会好一点,但是也没有执行完所有的异步操作,也就是说在资源不足的情况下,Tokio会抛弃某些任务,这不符合我们的预期。 **可以再达到了某一阀值的情况下阻塞一下,不再给Tokio新的任务呢?** 这有点类似线程池,当达达最大线程数的时候阻塞后面的任务待有释放的线程后再继续。 **可以使用 JoinSet 来管理派生出来的任务。** 使用 `JoinSet` 来管理派生出来的任务,可以确保至少一个任务被执行完成。 **结合set的len,我们可以可以在任务达到上限时阻塞任务派生。** 当循环结束,可能还有未完成的任务,所以只要 `set.len()`大于0就等待任务结束。

正文

作者:京东科技 贾世闻

Tokio 无疑是 Rust 世界中最优秀的异步Runtime实现。非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能。

我们看看下面的例子

fn main(){


        let max_task = 1;


        let rt = runtime::Builder::new_multi_thread()


            .worker_threads(max_task)


            


            .build()


            .unwrap();     


        rt.block_on(async {


            println!("tokio_multi_thread ");


            for i in 0..100 {


                println!("run {}", i);     


                tokio::spawn(async move {


                    println!("spawn {}", i);


                    thread::sleep(Duration::from_secs(2));


                });


            }


        });


    }

我们期待的运行结构是通过异步任务打印出99个 “spawn i",但实际输出的结果大概这样

tokio_multi_thread


run 0


run 1


run 2


.......


run 16


spawn 0


run 17


......


run 99


spawn 1


spawn 2


......


spawn 29


......


spawn 58


spawn 59

59执行完后面就没有输出了,如果把max_task设置为2,情况会好一点,但是也没有执行完所有的异步操作,也就是说在资源不足的情况下,Tokio会抛弃某些任务,这不符合我们的预期。那么能不能再达到了某一阀值的情况下阻塞一下,不再给Tokio新的任务呢。这有点类似线程池,当达达最大线程数的时候阻塞后面的任务待有释放的线程后再继续。

我们看看下面的代码。

fn main(){


        let max_task = 2;


        let rt = runtime::Builder::new_multi_thread()


            .worker_threads(max_task)


            .enable_time()


            .build()


            .unwrap();     


        let mut set = JoinSet::new();


        rt.block_on(async {


            for i in 0..100 {


                println!("run {}", i);


                while set.len() >= max_task {


                    set.join_next().await;


                }


                set.spawn(async move {


                    sleep().await;


                    println!("spawn {}", i);


                });


            }


            while set.len() > 0 {


                set.join_next().await;


            }


        });


    }

我们使用JoinSet来管理派生出来的任务。set.join_next().await; 保证至少一个任务被执行完成。结合set的len,我们可以在任务达到上限时阻塞任务派生。当循环结束,可能还有未完成的任务,所以只要set.len()大于0就等待任务结束。

输出大概长这样

running 1 test


tokio_multi_thread


run 0


run 1


spawn 0


run 2


spawn 1


......


run 31


spawn 30


run 32


spawn 31


run 33


......


run 96


spawn 95


run 97


spawn 96


run 98


spawn 97


run 99


spawn 98


spawn 99

符合预期,代码不多,有兴趣的同学可以动手尝试一下。

与文盘Rust -- 用Tokio实现简易任务池相似的内容:

文盘Rust -- 用Tokio实现简易任务池

Tokio 无疑是 Rust 世界中最优秀的异步Runtime实现。非阻塞的特性带来了优异的性能,但是在实际的开发中我们往往需要在某些情况下阻塞任务来实现某些功能。

文盘Rust -- 本地库引发的依赖冲突

clickhouse 的原生 rust 客户端目前比较好的有两个clickhouse-rs 和 clickhouse.rs 。两个库在单独使用时没有任何问题,但是,在同一工程同时引用时会报错。本篇内容主要讲解如何用rust语言解决本地库引发的依赖冲突问题

文盘Rust -- tonic-Rust grpc初体验

gRPC 是开发中常用的开源高性能远程过程调用(RPC)框架,tonic 是基于 HTTP/2 的 gRPC 实现,专注于高性能、互操作性和灵活性。该库的创建是为了对 async/await 提供一流的支持,并充当用 Rust 编写的生产系统的核心构建块。今天我们聊聊通过使用tonic 调用grpc的的具体过程。

文盘Rust -- 把程序作为守护进程启动

当我们写完一个服务端程序,需要上线部署的时候,或多或少都会和操作系统的守护进程打交道,毕竟谁也不希望shell关闭既停服。今天我们就来聊聊这个事儿。 最早大家部署应用的通常操作是 “nohup xxxx &”,别说像weblogic 或者其他java 容器有启动脚本,里面其实也差不多;很喜欢 ngi

文盘Rust -- r2d2 实现redis连接池

作者:贾世闻 我们在开发应用后端系统的时候经常要和各种数据库、缓存等资源打交道。这一期,我们聊聊如何访问redis 并将资源池化。 在一个应用后端程序访问redis主要要做的工作有两个,单例和池化。 在后端应用集成redis,我们主要用到以下几个crate:​ ​once_cell​​​、​ ​re

文盘Rust -- rust 连接云上数仓 starwift

最近想看看 rust 如何集成 clickhouse,又犯了好吃懒做的心理(不想自己建环境),刚好京东云发布了兼容ck 的云原生数仓 Starwfit,于是搞了个实例折腾一番。 Starwfit 是京东云自主研发的新一代云原生数据仓库,通过存算分离降低了存储成本,同时兼具性能和扩展弹性。其写入和查询速度可达到传统数据仓库的数倍,为用户提供实时数据分析能力。广泛应用于流量分析、精准营销、用户画像、广

文盘Rust -- 领域交互模式如何实现

书接上文,上回说到如何通过interactcli-rs四步实现一个命令行程序。但是 shell 交互模式在有些场景下用户体验并不是很好。比如我们要连接某个服务,比如 mysql 或者 redis 这样的服务。如果每次交互都需要输入地址、端口、用户名等信息,交互起来太麻烦。通常的做法是一次性输入和连接相关的信息或者由统一配置文件进行管理,然后进入领域交互模式,所有的命令和反馈都和该领域相关。inte

文盘Rust -- 安全连接 TiDB/Mysql

最近在折腾rust与数据库集成,选了Tidb Cloud Serverless Tier 作为数据源。Tidb 无疑是近五年来最优秀的国产开源分布式数据库,Tidb Cloud Serverless Tier作为pingcap旗下的云产品方便又经济,这次使用还有一些小惊喜。

文盘Rust -- FFI 浅尝

rust FFI 是rust与其他语言互调的桥梁,通过FFI rust 可以有效继承 C 语言的历史资产。本期通过几个例子来聊聊rust与C 语言交互的具体步骤

文盘Rust -- Mutex解决并发写文件乱序问题

在实际开发过程中,我们可能会遇到并发写文件的场景,如果处理不当很可能出现文件内容乱序问题。下面我们通过一个示例程序描述这一过程并给出解决该问题的方法。