文盘 Rust -- tokio 绑定 cpu 实践

2023-09-18 09:10:04

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 的监控如下:

可以看到每个 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 上。

上面的代码只是把负载绑定到了一个 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 上。代码运行的监控如下图。

更多推荐

软件设计模式系列之十一——装饰模式

当谈到设计软件系统时,经常需要考虑如何使系统更加灵活、可扩展和易维护。设计模式是一种被广泛采用的方法,用于解决常见的设计问题,并提供了一套可重用的解决方案。装饰模式(DecoratorPattern)是一种结构型设计模式,它允许您在不改变对象接口的情况下动态地添加对象的功能或责任。在本文中,我们将深入探讨装饰模式,包括

ChatGLM P-Tuningv2微调定制AI大模型

前言什么是模型微调想象一下,你正在学习如何弹奏一首钢琴曲目。你已经学会了一些基本的钢琴技巧,但你想要更进一步,尝试演奏一首特定的曲目。这时,你会选择一首你感兴趣的曲目,并开始深度练习。Fine-tuning(微调)在机器学习中也是类似的概念。当我们使用预先训练好的模型(预训练Pre-training)来解决一个特定的任

【uniapp】小程序开发:2 安装uni-ui组件库、使用pinia状态管理、自定义http请求

一、安装uni-ui组件库1、安装pnpmi-Dsasspnpmi@dcloudio/uni-ui2、配置组件自动导入使用npm安装好uni-ui之后,需要配置easycom规则,让npm安装的组件支持easycom打开项目根目录下的pages.json并添加easycom节点://pages.json{"easyco

Remix v2 + Cloudflare Pages 集成 Github 登录

RemixAuth特性完整的服务器端身份验证完整的TypeScript支持基于策略的身份验证轻松处理成功和失败实施自定义策略支持持久会话文章目录RemixAuth特性安装依赖封装服务登录及回调登出/注销TypeScript类型FAQ安装依赖npmi--saveremix-authremix-auth-github需要用

【ArcGIS】基本概念-矢量空间分析

栅格数据与矢量数据1.1栅格数据栅格图是一个规则的阵列,包含着一定数量的像元或者栅格常用的栅格图格式有:tif,png,jpeg/jpg等1.2矢量数据矢量图是由一组描述点、线、面,以及它们的色彩、位置的数据,通过软件算法计算得到的图形。常用的矢量图格式有:shp、eps、dwg、dxf等GIS中矢量数据可以分为地图层

阿里云CDN架构接入WAF应用防火墙案例实践

文章目录1.网站架构变化2.配置WAF应用防火墙2.1.配置网站接入WAF防火墙2.2.WAF防火墙生成CNAME地址2.3.配置WAF防火墙HTTPS证书2.4.WAF防火墙开启HTTP回源SLB3.配置CDN加速器回源WAF防火墙4.将域名DNS解析指向CDN的域名5.测试网站是否能正常访问6.模拟攻击观察WAF的

基于微信小程序的小区服务管理系统设计与实现(源码+lw+部署文档+讲解等)

前言💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗👇🏻精彩专栏推荐订阅👇🏻2023-2024年最值得选的微信小程序毕业设计选题大全:100个热门选

【Linux】线程的概念

文章目录📖前言1.线程的引入1.1执行流:1.2线程的创建:1.3线程的等待:2.查看线程2.1链接线程库:2.2ps-aL:2.3获取线程的LWP:3.页表的认识3.1二级页表:3.2页表的实际大小:4.再看线程4.1线程总结:4.2线程的优点:4.3线程的缺点:📖前言从本章开始,我们进入Linux系统编程最后一

HarmonyOS应用开发者基础认证考试题目及答案

小试了一下HarmonyOS应用开发者基础认证考试,顺利通过,下面试题及答案。不过考试好像每次题目不尽相同,好像是抽取的,仅供参考。【判断题】1.所有使用@Component修饰的自定义组件都支持onPageShow,onBackPress和onPageHide生命周期函数。(错)2.每一个自定义组件都有自己的生命周期

【TypeScript】项目中对于TypeScript的打包处理

webpack通常情况下,实际开发中我们都需要使用构建工具对代码进行打包,TS同样也可以结合构建工具一起使用,下边以webpack为例介绍一下如何结合构建工具使用TS。步骤:初始化项目进入项目根目录,执行命令npminit-y主要作用:创建package.json文件下载构建工具npmi-Dwebpackwebpack

自动化项目实战:用requests库自动保存王者荣耀英雄皮肤到本地,文末附源码下载!

前言王者荣耀是一款备受欢迎的手机游戏,拥有众多精美的英雄皮肤。如果你想获取这些皮肤的图片或者其他相关信息,可以利用Python编写一个简单的爬虫来实现。安装第三方库首先,我们需要安装Python的requests和BeautifulSoup库。可以使用以下命令来安装它们:pipinstallrequestspipins

热文推荐