文盘Rust -- tokio绑定cpu实践 | 京东云技术团队

news/2024/11/2 16:24:37/

tokio 是 rust 生态中流行的异步运行时框架。在实际生产中我们如果希望 tokio 应用程序与特定的 cpu core 绑定该怎么处理呢?这次我们来聊聊这个话题。

首先我们先写一段简单的多任务程序。

use tokio::runtime;
pub fn main() {let rt = runtime::Builder::new_multi_thread().enable_all().build().unwrap();rt.block_on(async {for i in 0..8 {println!("num {}", i);tokio::spawn(async move {loop {let mut sum: i32 = 0;for i in 0..100000000 {sum = sum.overflowing_add(i).0;}println!("sum {}", sum);}});}});
}

程序非常简单,首先构造一个tokio runtime 环境,然后派生多个 tokio 并发,每个并发执行一个无限循环做overflowing_add。overflowing_add函数返回一个加法的元组以及一个表示是否会发生算术溢出的布尔值。如果会发生溢出,那么将返回包装好的值。然后取元祖的第一个元素打印。

这个程序运行在 Ubuntu 20 OS,4 core cpu。通过nmon的监控如下:

tokio_cpu_affinity_01

可以看到每个 core 都有负载。

要想把负载绑定在某一 core 上,需要使用core_affinity_rs。core_affinity_rs是一个用于管理CPU亲和力的Rust crate。目前支持Linux、Mac OSX和Windows。官方宣称支持多平台,本人只做了linux 操作系统的测试。

我们把代码修改一下:

use tokio::runtime;pub fn main() {let core_ids = core_affinity::get_core_ids().unwrap();println!("core num {}", core_ids.len());let core_id = core_ids[1];let rt = runtime::Builder::new_multi_thread().on_thread_start(move || {core_affinity::set_for_current(core_id.clone());}).enable_all().build().unwrap();rt.block_on(async {for i in 0..8 {println!("num {}", i);tokio::spawn(async move { loop {let mut sum: i32 = 0;for i in 0..100000000 {sum = sum.overflowing_add(i).0;}println!("sum {}", sum);           }});}});
}

在构建多线程runtime时,在on_thread_start 设置cpu亲和。可以看到负载被绑定到了指定的core上。

tokio_cpu_affinity_02

上面的代码只是把负载绑定到了一个core上,那么要绑定多个核怎么办呢?
我们看看下面的代码

pub fn main() {let core_ids = core_affinity::get_core_ids().unwrap();println!("core num {}", core_ids.len());let rt = runtime::Builder::new_multi_thread().enable_all().build().unwrap();let mut idx = 2;rt.block_on(async {for i in 0..8 {println!("num {}", i);let core_id = core_ids[idx];if idx.eq(&(core_ids.len() - 1)) {idx = 2;} else {idx += 1;}tokio::spawn(async move {let res = core_affinity::set_for_current(core_id);println!("{}", res);loop {let mut sum: i32 = 0;for i in 0..100000000 {sum = sum.overflowing_add(i).0;}println!("sum {}", sum);}});}});
}

代码需要把所有负载绑在 core3和core4上。原理是在派生任务中加入 core_affinity 设置.通过调整idx,将派生并发平均绑定在指定的core上。代码运行的监控如下图。

tokio_cpu_affinity_03

本期关于cpu亲和的话题就聊到这儿,下期见

作者:京东科技 贾世闻

来源:京东云开发者社区


http://www.ppmy.cn/news/221890.html

相关文章

我踩过的那些坑,浅谈一下如何更优雅地使用 Linux

前言 相信很多尝鲜过桌面 Linux 系统的朋友,对它一个很深刻的印象就是稳定性差:不知道怎么就把系统搞崩了,又找不到问题的具体原因和解决方法,只能尝试重装,直到心力交瘁地回到了 Windows 或 macOS。但另一方面&#…

Linux之动态库和静态库

文章目录 前言一、动态库和静态库概念二、库三、制作静态库1. 创建Makefile:2.打包库3.使用库总结注意库的安装 四、制作动态库总结 五、动静态库的加载总结 前言 一、动态库和静态库概念 在之前的文章中,介绍过动静态库的概念,因此这次我们…

常见JavaScript加密算法、JS加密算法

常见JavaScript加密算法、JS加密算法 一、SHA-256加密算法二、Base64编码算法三、RSA加密算法四、AES加密算法五、HMAC-SHA256算法六、PKCS7填充 一、SHA-256加密算法 SHA-256是一种密码散列函数,可以将任意长度的消息压缩成256位的摘要值。以下是使用JavaScript实现…

【2023】华为OD机试真题Java CC++ Python JS Go-题目0244-Linux发行版的数量

题目0244-Linux发行版的数量 题目描述 Linux 操作系统有多个发行版,distrowatch.com 提供了各个发行版的资料。这些发行版互相存在关联,例如 Ubuntu 基于Debian 开发,而 Mint 又基于 Ubuntu 开发,那么我们认为 Mint 同 Debian 也存在关联。 发行版集是一个或多个相关存在…

MySQL查询序号带小数点问题

案例: SELECT (num:num1) AS index, name, age FROM sys_user, (SELECT num:0) AS a order by age,name; 查询结果: datagrip和dbeaver查询结果不一样,使用cmd查询,默认也是无小数点的 但实际返回结果,其实是带点的 D…

实现排行榜功能

这篇博客主要是为了给朋友讲解的 她的项目是使用uniapp来实现的 写的比较急 不对的也可以指出来 主要是为了实现排行榜功能 切换不同的排行榜 vue中class的绑定 (当有一个确定的公共的class类名 加一个不确定(点击邀请好友时显示的样式)的类名 ) 仔细看两者是有区别的 特别注意…

spring redis 实现排行榜

https://docs.spring.io/spring-data/redis/docs/current/api/ org.springframework.data.redis.core.SetOperations 核心方法解析 add(K key, V... values)Add given values to set at key. 插入数据 // 不存在则添加,存在则添加失败NullableBoolean addIfAbsent(…

laravel + redis 实现排行榜

1.控制器 这里为什么要用redis 有序集合 (sorted set) 因为 Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。 不同的是每个元素都会关联一个 double 类型的分数。redis 正是通过分数来为集合中的成员进行从小到大的排序。 有序集合的成员是唯一的…