详解Rust多线程编程
文章目录
- 多线程模型
- 创建和管理线程
- 自定义线程行为
- 线程传递数据
- 线程间通信
- 线程池
- 错误处理与线程
- Condvar(条件变量)
- 无锁并发
- 高性能并发库
Rust的多线程编程提供了一种安全、高效的方式来进行并发操作。Rust的并发性设计原则之一是确保线程安全,同时避免运行时的开销,这使得它在多线程编程上有显著的优势。Rust通过其所有权系统、类型系统和并发原语,能够在编译时避免数据竞争和内存错误,从而使并发编程变得更安全。
多线程模型
Rust多线程模型通过所有权系统和借用检查系统确保在多线程环境中,数据不会被多个线程同时修改,数据可以通过所有权转移或引用传递给不同的线程,从而避免数据竞争。
创建和管理线程
Rust中的线程通过标准库中的std::thread模块来创建和管理。
//使用thread::spawn方法 创建线程
use std::thread;fn main() {// 创建一个线程let handle = thread::spawn(|| {println!("Hello from the thread!");});// handle.join()会阻塞主线程,直到子线程完成执行handle.join().unwrap();println!("Main thread finished.");
}
自定义线程行为
1.自定义线程名称
use std::thread;fn main() {let handle = thread::Builder::new().name("自定义线程".to_string()).spawn(|| {println!("当前线程: {:?}", thread::current().name());}).unwrap();handle.join().unwrap();
}
2.自定义线程栈大小
use std::thread;fn main() {let handle = thread::Builder::new().stack_size(4 * 1024 * 1024) // 4 MB 栈大小.spawn(|| {println!("线程运行中...");}).unwrap();handle.join().unwrap();
}
线程传递数据
在Rust中如果要从主线程将数据传递到子线程,通常通过所有权转移的方式。可以将数据通过move关键字传递给线程,或者使用Arc和Mutex来在多个线程之间共享数据。
use std::thread;fn main() {let data = String::from("Hello from main thread");//使用 move 关键字将数据的所有权传递给线程//move会捕获并转移闭包中所有的值,而不是借用它们 let handle = thread::spawn(move || {//现在 data 的所有权在子线程中println!("{}", data); });handle.join().unwrap(); // 等待线程结束
}
线程间通信
在Rust中线程间的通信通常通过以下两种方式进行:
1.Channels(通道): Rust提供了一个强类型的、基于消息传递的通道,用于线程间传递数据。Rust标准库提供了std::sync::mpsc(多生产者单消费者)模块来实现这种机制。
2.共享内存: 通过Arc(原子引用计数)和Mutex(互斥锁)组合,可以在多个线程间共享数据并保证线程安全。
使用通道进行线程间通信的调用实例如下所示:
单向通信,单个发送者和单个接收者
use std::thread;
use std::sync::mpsc;fn main() {//创建一个通道let (tx, rx) = mpsc::channel();//启动一个线程,发送数据到主线程thread::spawn(move || {let message = String::from("Hello from the thread!");tx.send(message).unwrap(); // 发送数据});//主线程接收数据let received = rx.recv().unwrap(); // 阻塞直到收到消息println!("Received: {}", received);
}
多个发送者进行通信
use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();let tx1 = tx.clone();thread::spawn(move || {tx.send("线程1的消息").unwrap();});thread::spawn(move || {tx1.send("线程2的消息").unwrap();});for received in rx.iter().take(2) {println!("主线程接收到: {}", received);}
}
如果多个线程需要共享同一份数据,可以使用Arc和Mutex。
Arc是一个线程安全的引用计数类型,允许多个线程共享同一个数据。
Mutex是一个互斥锁,用于保护共享数据,确保只有一个线程能够同时访问数据。
use std::sync::{Arc, Mutex};
use std::thread;fn main() {//创建一个 Mutex 包装的数据//Mutex确保每次只有一个线程能修改计数器的值,Arc允许线程安全地共享该Mutex let counter = Arc::new(Mutex::new(0)); let mut handles = vec![];for _ in 0..10 {//克隆Arc获取新的引用let counter = Arc::clone(&counter); let handle = thread::spawn(move || {//如果线程未释放锁,其他线程会阻塞等待let mut num = counter.lock().unwrap(); // 获取锁*num += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}// 输出最终的计数结果println!("Result: {}", *counter.lock().unwrap());
}
线程池
对于有大量短任务的应用,创建和销毁大量线程会有不小的性能开销。为了避免这种情况,可以使用线程池。Rust标准库本身不提供线程池,但可以使用rayon或tokio等第三方库。
1.Rayon专注于并行数据处理,适用于数据并行任务,如并行迭代器。
2.Tokio适用于异步编程,但也支持多线程和线程池。
在Cargo.toml文件中导入第三方库
[dependencies]
rayon = "1.5"
Rayon线程池示例
use rayon::prelude::*;
//Rayon库使得处理数据并行变得更加容易,它自动管理线程池,简化了多线程编程
fn main() {let numbers = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];let sum: i32 = numbers.par_iter() //并行迭代器.map(|&x| x * x) //每个元素平方.sum(); //求和println!("Sum of squares: {}", sum);
}
错误处理与线程
多线程编程中,错误处理是一个重要的方面。Rust提供了Result类型来处理错误。在多线程中,可以通过join方法来获取线程的结果,如果线程出现错误,join会返回一个Result,可以对错误进行处理。
use std::thread;fn main() {let handle = thread::spawn(|| {//模拟错误panic!("Something went wrong!");});let result = handle.join();match result {Ok(_) => println!("Thread finished successfully"),Err(e) => println!("Thread failed: {:?}", e),}
}
Condvar(条件变量)
条件变量(Condvar)是Rust中一个重要的同步原语,用于实现线程间的协调和等待机制。它允许一个线程等待某个条件变为真,而另一个线程通知条件的改变。主要用于线程间的复杂同步,结合Mutex用来等待和唤醒线程。
use std::sync::{Arc, Condvar, Mutex};
use std::thread;fn main() {let pair = Arc::new((Mutex::new(false), Condvar::new()));let pair_clone = Arc::clone(&pair);thread::spawn(move || {let (lock, cvar) = &*pair_clone;let mut started = lock.lock().unwrap();*started = true;cvar.notify_one();});let (lock, cvar) = &*pair;let mut started = lock.lock().unwrap();while !*started {started = cvar.wait(started).unwrap();}println!("线程已启动");
}
无锁并发
Rust支持无锁并发,通过原子操作或无锁数据结构避免锁的开销。使用std::sync::atomic提供的原子类型如AtomicUsize实现无锁计数
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;fn main() {let counter = AtomicUsize::new(0);let handles: Vec<_> = (0..10).map(|_| {thread::spawn(|| {for _ in 0..1000 {counter.fetch_add(1, Ordering::Relaxed);}})}).collect();for handle in handles {handle.join().unwrap();}println!("计数结果: {}", counter.load(Ordering::Relaxed));
}
高性能并发库
Rust生态中提供了许多高性能并发库,满足不同场景需求:
1.Rayon 数据并行化处理
2.Crossbeam 高性能线程间通信和无锁数据结构
3.Tokio 异步编程框架,支持高性能 I/O
4.async-std 轻量级异步运行时,类似Tokio
5.Threadpool 简单易用的线程池
相关文章:
详解Rust多线程编程
文章目录 多线程模型创建和管理线程自定义线程行为线程传递数据线程间通信线程池错误处理与线程Condvar(条件变量)无锁并发高性能并发库 Rust的多线程编程提供了一种安全、高效的方式来进行并发操作。Rust的并发性设计原则之一是确保线程安全,同时避免运行时的开销&…...
Uniapp触底刷新
在你的代码中,使用了 scroll-view 来实现一个可滚动的评论区域,并且通过监听 scrolltolower 事件来触发 handleScrollToLower 函数,以实现“触底更新”或加载更多评论的功能。 关键部分分析: scroll-view 组件: scroll-view 是一…...
【前端】安装hadoop后,前端启动报错,yarn命令
新安装hadoop后,前端启动项目用yarn命令,报错。 报错:系统找不到指定的路径。 No HADOOP_CONF_DIR set. Please specify it either in yarn-env.cmd or in the environment. 解决:删掉hadoop目录下yarn的文件 检查:…...
T620存储安全方案SoC芯片技术手册
系统资源 集成32位国产CPU CK803S;最高工作频率260Mhz CK803S内置16KB I/D Cache,内置32KB DTCM 32KB ROM;256KB SRAM;8KB SRAM(系统专用) 512KB/1MB 片内Flash 安全算法 支持SM4数据加密,加密性…...
Rust循环引用与多线程并发
循环引用与自引用 循环引用的概念 循环引用指的是两个或多个对象之间相互持有对方的引用。在 Rust 中,由于所有权和生命周期的严格约束,直接创建循环引用通常会导致编译失败。例如: // 错误的循环引用示例 struct Node {next: Option<B…...
力扣 二叉树的锯齿形层序遍历-103
二叉树的锯齿形层序遍历-103 此题就是再二叉树层序遍历的基础上,加了反转当前层数组元素的函数reverse(),也可以不反转,直接在遍历当前层的所有节点的for循环里直接进行if判断,根据遍历方向,决定如何插入元素。 clas…...
PyCryptodome:Python中的密码学库
简介 PyCryptodome是一个功能强大的Python密码学库,提供了各种密码学算法的实现,包括对称加密、非对称加密、哈希函数、消息认证码等。它是对Python的Crypto库的一个现代化和增强版,提供了更好的性能和安全性。 Git地址 PyCryptodome的代码可…...
我眼中的“懂重构”(一)
初识重构 2017年的时候,领导让我看公司的一本书《重构——改善代码的既有设计》,这是一本JAVA版本的,前后看了2遍。那时候看书因为不懂看的格外仔细。我只是那时候不懂,然而多年后的今天我仍然发现很多人对重构充满误解。在刚进入…...
Excel中日期格式“年月日 时间”修改为“年月日”
需求: 将Excel中“yyyy-mm-dd hh:mm:ss”格式的时间转换为“yyyy-mm-dd”格式的时间,选中转换后的时间时编辑栏中依然会显示“yyyy-mm-dd hh:mm:ss”格式。 方法一、在原数据列进行转换: 1、选中需要转换的数据列,右键--【设置…...
CSS底层基础:小白速来
1. CSS简介 CSS (Cascading Style Sheets) 是一种用来描述HTML或XML文档样式的语言。它使得开发者能够控制网页的布局和外观,包括字体、颜色、间距等。CSS通过选择器来指定要应用样式的元素,并定义这些元素的具体样式属性。 基本结构示例: …...
【MySQL】库和表的基本操作
目录 库 库的增删查改 字符集与校验集 库的备份与恢复 表 表的创建和删除 用不同的存储引擎创建表的区别 查看表 修改表 添加删除属性 修改改变属性 上篇博客我们讲了数据库的基本理解,对数据库有了一个大致的概念,下面我们来介绍一下库和表的…...
5款AI智能办公工具丨提升办公效率‼️
办公效率低?工作压力大?别担心,这里有五款超实用的AI办公工具,帮你轻松搞定各种任务!🌟 简直不要太实用,快快收藏起来总有一天你会用得上~ 红薯通AI📝写作文案的好帮手,…...
华为HarmonyOS 让应用快速拥有账号能力 -- 3 获取用户手机号
场景介绍 当应用对获取的手机号时效性要求不高时,可使用Account Kit提供的手机号授权与快速验证能力,向用户发起手机号授权申请,经用户同意授权后,获取到手机号并为用户提供相应服务。以下只针对Account kit提供的手机号授权与快…...
lambda strem流表达式处理工具
一个通用的lambda stream流处理工具, 包含了工作中绝大部分场景常用的使用方式 import java.math.BigDecimal; import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.funct…...
Android 编译和使用libheif
项目中需要使用libheif,libde265,libyuv。一下是相应的cmakelist.txt。这里直接使用了静态库。 里面涉及到c包的链接,需要stdc。 ${PROJECT_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}/liblibde265.a这个路径由于操作过程中copy出现问题,多了一层路径&…...
新一代零样本无训练目标检测
🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年12月2日21点02分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅h…...
神经网络入门实战:(九)分类问题 → 神经网络模型搭建模版和训练四步曲
(一) 神经网络模型搭建官方文档 每一层基本都有权重和偏置,可以仔细看官方文档。 pytorch 官网的库:torch.nn — PyTorch 2.5 documentation Containers库:用来搭建神经网络框架(包含所有的神经网络的框架);…...
写NFC微信小程序跳转Uri标签
本示例使用的发卡器:https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1b8bEEGz&ftt&id615391857885 Dim dispstr As String Dim status As Byte Dim status1 As Byte Dim afi As Byte Dim myctrlword As Byte Dim mypiccserial(0 To 7) …...
Gradle vs. Maven: 到底哪个更适合java 项目?
ApiHug ApiHug - API Design & Develop New Paradigm.ApiHug - API Design & Develop New Paradigm.https://apihug.com/ 首先 ApiHug 整个工具链是基于 gradle 构建,包括项目模版, 插件; 说到 Java 项目管理,有两个巨头脱颖而出&a…...
【赛博保安】安全日记之常用术语(一)
"企业的信息安全治理水平,直接取决于安全团队人员的技术专业度,而非运营经验值。所谓的技术,并非指渗透和挖洞的能力,而是指软件开发、IT 架构、网络拓扑相关的知识和经验。 站在乙方的角度来看,技术薄弱的安全人…...
设计模式 更新ing
设计模式 1、六大原则1.1 单一设计原则 SRP1.2 开闭原则1.3 里氏替换原则1.4 迪米特法则1.5 接口隔离原则1.6 依赖倒置原则 2、工厂模式 1、六大原则 1.1 单一设计原则 SRP 一个类应该只有一个变化的原因 比如一个视频软件,区分不同的用户级别 包括访客࿰…...
008静态路由-特定主机路由
按照如上配置,用192.168.0.1 电脑ping 192.168.1.1 发现能够ping通 用192.168.0.1 电脑ping 192.168.2.1 发现不能ping通 这是因为192.168.0.1 和 192.168.1.1 使用的是同一个路由器R1。 192.168.0.1 和 192.168.2.1 通信需要先经过R1,再经过R2 …...
MySQL 慢查询日志记录 SQL优化 性能优化 日志查询 Explain
介绍 慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。MySQL的慢查询日志默认没有开启,需要在MySQL的配置文件(/etc/my.cnf)中配置针对这些慢查询的SQL语句进行优化。 #开启慢查询开关 s…...
VINS_MONO视觉导航算法【三】ROS基础知识介绍
文章目录 其他文章说明ROSlaunch文件基本概念定义用途 文件结构根标签常用标签\<node>\<param>\<rosparam>\<remap>\<include>\<arg>\<group> 示例基本示例嵌套示例 使用方法启动 *.launch 文件传递参数 总结 ROS topicTopic 的基本…...
Python 3 教程第13篇(集合)
Python3 集合 集合(set)是一个无序的不重复元素序列。 集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。 可以使用大括号 { } 创建集合,元素之间用逗号 , 分隔, 或者也可以使用 set() 函数创建集…...
cesium 3dtile ClippingPlanes 多边形挖洞ClippingPlaneCollection
原理就是3dtiles里面的属性clippingPlanes 采用ClippingPlaneCollection,构成多边形来挖洞。 其次就是xyz法向量挖洞 clippingPlanes: new this.ffCesium.Cesium.ClippingPlaneCollection({unionClippingRegions: true, // true 表示多个切割面能合并为一个有效的…...
开发者如何使用GCC提升开发效率GUI操作
看此篇前请先阅读https://blog.csdn.net/qq_20330595/article/details/144139026?spm1001.2014.3001.5502 先上效果图 找到对应的环境版本 配置环境 目录结构 CtrlShiftP c_cpp_properties.json {"configurations": [{"name": "Win32","i…...
什么是隐式类型转换?
隐式类型转换(Implicit Type Conversion)是指编译器在没有明确要求的情况下,自动地将一种类型的值转换为另一种类型。C 语言支持隐式类型转换,这通常发生在表达式运算或函数调用中,以确保操作数或参数的类型兼容性。 隐…...
爬虫专栏第三篇:Python 实战:运用 requests 突破京东商品评论获取难题(含 cookie 处理与编码设置技巧
简介:本文以京东商品评论为例,详细介绍了使用requests库获取网页数据的过程,包括从打开商品评价页面、抓包分析找到评论接口,到处理cookie参数、解决cookie字符串解析问题,以及设置正确的编码以成功获取评论数据&#…...
HCIE:详解OSPF,从基础到高级特性再到深入研究
目录 前言 一、OSPF协议基本原理 简介 基本原理 OSPF路由器类型 OSPF网络类型 OSPF报文类型和封装 OSPF邻居的建立的维护 DR和BDR的选举 伪节点 LSDB的更新 OSPF的配置 二、OSPF的高级特性 虚连接(Virtual-Link) OSPF的LSA和路由选择 OSPF…...
第六十六条:谨慎使用本地方法
其实在java中有很多都是采用C或C语言实现的比如native这种的本地方法,感兴趣的可以找源代码看看。 Java Native Interface (JNI) 允许Java应用程序可以调用本地方法(native method),所谓本地方法是指使用本地程序设计语言…...
neo4j如何存储关于liquidity structure的层次和关联结构
在 Neo4j 中存储关于流动性结构(liquidity structure)的层次和关联结构非常适合,因为 Neo4j 是一个基于图的数据库,能够自然地建模和存储复杂的关系和层次结构。下面是如何在 Neo4j 中设计和实现这样的数据模型的详细步骤和示例。…...
45 基于单片机的信号选择与温度变化
目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 基于51单片机,采用DS18B20检测温度,通过三种LED灯代表不同状态。 采用DAC0832显示信号脉冲,通过8位数码管显示温度。 信号脉冲可以根据两个按键分别调整为正弦…...
2、Three.js初步认识场景Scene、相机Camera、渲染器Renderer三要素
三要素之间关系: 有了虚拟场景Scene,相机录像Camera,在相机小屏幕上看到的Renderer Scene当前空间 Mesh人在场景 Camera相机录像 Renderer显示器上 首先先描述下Scene: 这个场景为三要素之一,一切需要展示的东西都需…...
Java基础面试题06:hashCode()和equals()方法的重要性体现在什么地方?
前言 Java中的hashCode()和equals()方法看似是干同一件事,但它们的使用场景和作用却大有不同。为了让程序更高效、更准确地运行,我们需要对这两者有深入的了解,并掌握它们的重写规则。 hashCode()和equals()的基础知识 什么是hashCode&…...
Matlab Simulink HDL Coder开发流程(一)— 创建HDL兼容的Simulink模型
创建HDL兼容的Simulink模型 一、使用Balnk DUT模板二、从HDL Coder库中选择模块三、为DUT开发算法/功能四、为设计创建Testbench五、仿真验证设计功能六、Simulink模型生成HDL代码 这个例子说明了如何创建一个用于生成HDL代码的Simulink模型。要创建兼容HDL代码生成的MATLAB算法…...
C#基础之方法
文章目录 1 方法1.1 定义方法1.2 参数传递1.2.1 按值传递参数1.2.2 按引用传递参数1.2.3 按输出传递参数1.2.4 可变参数 params1.2.5 具名参数1.2.6 可选参数 1.3 匿名方法1.3.1 Lambda 表达式1.3.1.1 定义1.3.1.2 常用类型1.3.1.3 Lambda 表达式与 LINQ1.3.1.4 Lambda 表达式的…...
Pytest框架学习19--参数化2
1、数据源是yaml 安装yaml,使用safe_load方法读取文件,解析出数据 pip install PyYAML # test_data.yaml test_case_1:a: 2b: 3expected_result: 5test_case_2:a: -1b: 10expected_result: 9test_case_3:a: 0b: 0expected_result: 0# test_code.pyimpor…...
VSCode中“Run Code”运行程序时,终端出现中文乱码解决方法
问题描述 在VSCode中“Run Code”运行程序时,终端输出结果出现中文乱码现象: 解决方法 1. 检查系统cmd的默认编码 查看Windows终端当前编码方式的命令: chcp输出结果是一段数字代码,如936,这说明当前的cmd编码方式…...
HarmonyOS 5.0应用开发——列表(List)
【高心星出品】 文章目录 列表(List)列表介绍列表布局设置主轴方向设置交叉轴方向 列表填充分组列表填充 滚动条位置设置滚动位置滚到监听 列表项侧滑 列表(List) 列表介绍 列表作为一种容器,会自动按其滚动方向排列…...
C++设计模式外观模式(Facade)
什么是桥接模式? 桥接模式(Bridge Pattern)是一种结构型设计模式,它的核心目的是解耦抽象部分和实现部分,让它们可以独立变化。在简单的描述中,桥接模式可以让你在不修改原有代码的情况下,分别…...
《Python基础》之Numpy库
目录 简介 一、创建数组 1、根据列表创建数组 2、创建全0数组 3、创建全1数组 4、创建单位矩阵 5、创建随机数数组 二、查看数组的属性 三、 数组的操作 1、索引和切片 2、变形 3、拼接 (1)、vstack() 纵向拼接 (2)、hs…...
Python异步编程与API调用:提高效率与性能的实践指南
引言 在当今的软件开发领域,异步编程已成为提高应用程序性能和响应能力的关键技术。特别是在处理I/O密集型任务,如API调用时,异步编程能够显著提升效率。本文将通过一个具体的示例——使用Python的asyncio和aiohttp库来异步调用APIÿ…...
Zookeeper3.4.14集群安装
Zookeeper3.4.14三节点集群安装 为保证集群高可用,Zookeeper 集群的节点数最好是奇数,最少有三个节点,所以这里搭建一个三个节点的集群。(在一个节点模拟三节点,真实的三节点把ip替换一下即可,按照hadoop案件把网络打…...
电机驱动MCU介绍
电机驱动MCU是一种专为电机控制设计的微控制器单元,它集成了先进的控制算法和高性能的功率输出能力。 电机驱动MCU采用高性能的处理器核心,具有快速的运算速度和丰富的外设接口。它内置了专业的电机控制算法,包括PID控制、FOC(Fi…...
Python 面向对象编程详解
Python 面向对象编程详解 面向对象编程(OOP)是一种编程范式,它使用“对象”来设计软件。在 Python 中,面向对象编程非常强大,允许开发者通过类(class)和对象(object)来模…...
网络技术-不使用K8S情况下哪些方法可搭建服务链编排
在不使用Kubernetes(k8s)(或不使用Docker环境技术的)情况下,搭建服务链编排环境需要依赖其他服务编排和容器化技术,或者采用传统的虚拟机和服务管理方法。以下是一些可能的解决方案: 一、使用其…...
JVM_总结详解
1、CPU和内存的交互 了解jvm内存模型前,了解下cpu和计算机内存的交互情况。【因为Java虚拟机内存模型定义的访问操作与计算机十分相似】 有篇很棒的文章,从cpu讲到内存模型:[什么是java内存模型?] 在计算机中,cpu和内存的交互最…...
go语言 Pool实现资源池管理数据库连接资源或其他常用需要共享的资源
go Pool Pool用于展示如何使用有缓冲的通道实现资源池,来管理可以在任意数量的goroutine之间共享及独立使用的资源。这种模式在需要共享一组静态资源的情况(如共享数据库连接或者内存缓冲区)下非 常有用。如果goroutine需要从池里得到这些资…...
初级数据结构——邻接表
目录 前言一、定义与结构二、特点与性质三、构建方式四、操作与应用五、代码模版六、经典例题[1.——LCP 07. 传递信息](https://leetcode.cn/problems/chuan-di-xin-xi/description/)代码题解 [2.——547. 省份数量](https://leetcode.cn/problems/number-of-provinces/)代码题…...