作者:京东科技 贾世闻

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实现简易任务池的更多相关文章

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

    作者:京东云 贾世闻 最近想看看 rust 如何集成 clickhouse,又犯了好吃懒做的心理(不想自己建环境),刚好京东云发布了兼容ck 的云原生数仓 Starwfit,于是搞了个实例折腾一番. ...

  2. 文盘Rust -- struct 中的生命周期

    最近在用rust 写一个redis的数据校验工具.redis-rs中具备 redis::ConnectionLike trait,借助它可以较好的来抽象校验过程.在开发中,不免要定义struct 中的 ...

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

    当我们写完一个服务端程序,需要上线部署的时候,或多或少都会和操作系统的守护进程打交道,毕竟谁也不希望shell关闭既停服.今天我们就来聊聊这个事儿. 最早大家部署应用的通常操作是 "nohu ...

  4. 文盘Rust -- 给程序加个日志

    作者:贾世闻 日志是应用程序的重要组成部分.无论是服务端程序还是客户端程序都需要日志做为错误输出或者业务记录.在这篇文章中,我们结合[log4rs](https://github.com/estk/l ...

  5. 一文学会Rust?

    Rust是什么 Rust 是一个系统编程语言,它注重三个方面:安全,速度和并发性. 特征: 1.没有垃圾回收机制,没有运行时,效率超过c++,直逼c语言 2.内存安全,并发安全,没有空指针 3.极其丰 ...

  6. 使用Swashbuckle构建RESTful风格文档

    本次和大家分享的是Swagger to WebApi的nuget包Swashbuckle:因为项目需要统一api文档的风格,并要支持多种开发语言(C#,java,python),所以首先想到的是swa ...

  7. Django入门笔记

    Django入门笔记 **文档包含Django安装包.学习的笔记.代码等 安装 Django参考附件,只需要把附件拷贝到你需要的目录就行.Django是1.8.16版本 Python:在附件中,其中有 ...

  8. Git快速入门和常用命令

    一.快速入门 本地初始化一个项目 首先,你需要执行下面两条命令,作为 git 的基础配置,作用是告诉 git 你是谁,你输入的信息将出现在你创建的提交中. git config --global us ...

  9. webassembly

    为什么需要 WebAssembly 自从 JavaScript 诞生起到现在已经变成最流行的编程语言,这背后正是 Web 的发展所推动的.Web 应用变得更多更复杂,但这也渐渐暴露出了 JavaScr ...

  10. SCWS 中文分词

    SCWS 中文分词v1.2.3 开源免费的中文分词系统,PHP分词的上乘之选! 首页 下载 演示 文档 关于 服务&支持 API/HTTP 论坛 捐赠 源码@github 文档目录 SCWS- ...

随机推荐

  1. SVN报错:database is locked

    https://blog.csdn.net/k7arm/article/details/81168416 https://www.jianshu.com/p/aa9c67fcc407

  2. api进阶Day2(低级流)文件流的输出流、读取流。向文件中写入文本数据、读取文件中的字符串、用lambda表达式创建文件过滤器。

    文件流:输出流: package io; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...

  3. 使用idea从零编写SpringCloud项目-Feign

    ps:Fegin和Ribbon 其实是差不多的东西,Fegin里面也是集成了Ribbon,不过咱们写代码不是要优雅嘛,使用Feign就会优雅很多了,看着比直接使用Ribbon舒坦一点 就不重新构建项目 ...

  4. Java基础进阶内容 - 随笔

    JAVA进阶 1 对象序列化 1.1 对象要序列化要实现Serializable接口 1.2 然后通过ObjectInputStream 对象读入流来读入一个对象 new ObjectOutputSt ...

  5. 游戏内存优化之使用16位纹理/NPOT

    转自:https://blog.csdn.net/oqqQuZi1234567/article/details/41749599 图片文件大小和纹理内存占用是两码事.假设他们是帐篷.图片文件就相当于帐 ...

  6. 移动服务(f[i] [j] [k],这三个人,位置为a[i],j,k的最小价值)

    移动服务(f[i] [j] [k],这三个人,位置为a[i],j,k的最小价值) 题意 给出点之间到达价值,使用3个人处理一个序列,f[i] [j] [k],这三个人,每次处理序列中一个值,三个人中一 ...

  7. java的两种线程

    java中的两种线程     守护线程与用户线程 守护线程:就是服务于用户线程的线程,例如垃圾回收的线程及时最典型的守护线程.不需要上层逻辑的介入 用户线程:就是程序自己创建的线程 守护线程; 守护线 ...

  8. FIR滤波器的设计

    FIR数字滤波器的设计 线性相位FIR滤波器的特点 单位冲激响应:\(h(n),0\leq n\leq N-1\) 系统函数:\(H(z)=\sum_{n=0}^{N-1}h(n)z^{-n}\) 零 ...

  9. Web部署

    1.项目配置的理解 IDEA 中最重要的各种设置项,就是这个 Project Structre 了,关乎你的项目运行,缺胳膊少腿都不行.最近公司正好也是用之前自己比较熟悉的IDEA而不是Eclipse ...

  10. Keil Jlink没法找到STM32H750

    https://www.amobbs.com/thread-5713382-1-1.html MDK使用的是5.32,jlink使用的是9.2jlink驱动使用的是6.44b 删除工程下的JLinkS ...