【Rust自学】16.2. 使用消息传递来跨线程传递数据
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
16.2.1. 消息传递
有一种很流行而且能保证安全并发的技术(或者叫机制)叫做消息传递。在这种机制里,线程(或Actor)通过彼此间发送消息(数据)来进行通讯。
Go语言有一句名言是这么说的:Do not communicate by sharing memory; instead, share memory by communicating.(不要用共享内存来通信,要用通信来共享内存)
Go语言的并发机制体现了这种思想。Rust也提供了机遇消息传递的一种并发方式,具体的就是在Rust里实现就是使用Channel
(标准库提供)。Go语言里也有Channel
,思路差不多。
16.2.2. 理解Channel
可以将编程中的Channle
想象为定向水道,例如小溪或河流。如果你把橡皮鸭之类的东西放入河中,它会顺流而下,到达水道的尽头。
通道有两部分:发送端和接收端。发射端是将橡皮鸭放入河中的上游位置,接收端是橡皮鸭最终到达下游的位置。代码的一部分使用要发送的数据调用发送端上的方法,另一部分检查接收端是否有到达的消息。如果发送端或接收端其一掉线,则称通道已关闭。
具体的步骤:
- 调用发送端的方法,发送数据
- 接收端会检查和接收到达的数据
- 如果发送端、接收端中的任意一端被丢弃了,那么
Channel
就关闭了。
16.2.3. 创建channel
使用mpsc::channel
函数来创建Channel
。mpsc
表示multiple producer, single consumer(多个生产者、一个消费者),表示可以有多个发送端,但是只能有一个接收端。
调用这个函数返回一个元组(tuple,详见 3.3. 数据类型:复合类型),有两个元素,分别是发送端和接收端。
看个例子:
use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();thread::spawn(move || {let val = String::from("hi");tx.send(val).unwrap();});let received = rx.recv().unwrap();println!("Got: {received}");
}
-
首先使用
mpsc::channel
函数来创建Channel
,返回的元组使用模式匹配进行解构,分别用tx
和rx
表示发送端和接收端。 -
接下来创建了一个线程,使用
move
关键字表示发送端tx
的所有权被移至分线程内,线程必须拥有通道发送端的所有权才能往通道里发消息。
使用send
方法来发送消息,返回类型是Result
类型,如果接收端被丢弃了那么返回值就是Err
,反之就是Ok
。在这里面就简单地使用unwrap
进行错误处理即可,这样如果接收端被丢弃就会恐慌。 -
接收端有两个方法来获取消息,这里使用了
recv
方法(recieve的简写)。它会一直阻塞这个线程,直到有消息被传入为止。
消息被包裹在Result
类型中,有消息就返回Ok
,反之就是Err
,一样使用unwrap
简单地处理错误即可。
输出:
Got: hi
发送端send
方法
send
方法的参数是想要发送的数据,返回Result
类型。如果有问题(例如接收端已经被丢弃)就会返回Err
接收端的方法
-
recv
方法:阻止当前线程执行,直到Channel
中有值传来,一旦收到值,就返回Result
类型,如果发送端关闭了,就会收到Err
。 -
try_recv
方法:不会阻塞当前线程执行,立即返回Result
类型,有数据到达就是OK
变体包裹着传过来的数据;否则就返回错误。
通常是使用循环调用来检查try_recv
的结果。一旦有消息来了就开始处理,如果没来,那么这时候也可以执行其他指令。
16.2.4. channel
和所有权转移
所有权在消息传递中非常重要,它能帮你编写安全、并发的代码。
看个例子:
use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();thread::spawn(move || {let val = String::from("hi");tx.send(val).unwrap();println!("val is {val}");});let received = rx.recv().unwrap();println!("Got: {received}");
}
在刚才的代码上加了println!("val is {val}");
这句话。把值传入send
函数后想继续在线程里使用值。
输出:
$ cargo runCompiling message-passing v0.1.0 (file:///projects/message-passing)
error[E0382]: borrow of moved value: `val`--> src/main.rs:10:26|
8 | let val = String::from("hi");| --- move occurs because `val` has type `String`, which does not implement the `Copy` trait
9 | tx.send(val).unwrap();| --- value moved here
10 | println!("val is {val}");| ^^^^^ value borrowed here after move|= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)For more information about this error, try `rustc --explain E0382`.
error: could not compile `message-passing` (bin "message-passing") due to 1 previous error
错误在于借用了已经移动值val
。它的所有权已经在传入send
时移交出去了,所以就会报错。
下一个例子通过发送多个值来观察接受者等待的过程:
use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn main() {let (tx, rx) = mpsc::channel();thread::spawn(move || {let vals = vec![String::from("hi"),String::from("from"),String::from("the"),String::from("thread"),];for val in vals {tx.send(val).unwrap();thread::sleep(Duration::from_secs(1));}});for received in rx {println!("Got: {received}");}
}
- 分线程以循环的方式发送
Vector
里的各个元素,每次发送完之后会暂停1秒 - 主线程接收端被当了一个迭代器来使用(因为实现了
iterator
trait),这样就不需要显式调用recv
函数了。每收到一个值就将它打印出来。当发送端执行完毕被丢弃时,Channel
就关闭了,循环就不会继续。程序退出。
输出:
Got: hi
Got: from
Got: the
Got: thread
16.2.5. 通过克隆创建多个发送者
继续在上一个代码的基础上稍作修改:
use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn main(){let (tx, rx) = mpsc::channel();let tx1 = tx.clone();thread::spawn(move || {let vals = vec![String::from("hi"),String::from("from"),String::from("the"),String::from("thread"),];for val in vals {tx1.send(val).unwrap();thread::sleep(Duration::from_secs(1));}});thread::spawn(move || {let vals = vec![String::from("more"),String::from("messages"),String::from("for"),String::from("you"),];for val in vals {tx.send(val).unwrap();thread::sleep(Duration::from_secs(1));}});for received in rx {println!("Got: {received}");}
}
这里多了一个分线程,现在有2个分线程都想要给主线程发消息,所以就需要两个发送端。针对这种情况,只需要对代表发送端的变量tx
使用clone
方法即可,也就是原文的let tx1 = tx.clone();
这一句。
输出:
Got: hi
Got: more
Got: from
Got: messages
Got: for
Got: the
Got: thread
Got: you
接收端收到的数据是交替出现的。
相关文章:

【Rust自学】16.2. 使用消息传递来跨线程传递数据
喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 16.2.1. 消息传递 有一种很流行而且能保证安全并发的技术(或者叫机制)叫做消息传递。在这种机制里,线…...

如何实现滑动网格的功能
文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了SliverList组件相关的内容,本章回中将介绍SliverGrid组件.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 我们在本章回中介绍的SliverGrid组件是一种网格类组件,主要用来…...
使用C# 如何获取本机连接的WIFI名称[C# ---1]
前言 楼主最近在写一个WLAN上位机,遇到了使用C#查询SSID 的问题。CSDN上很多文章都比较老了,而且代码过于复杂。楼主自己想了一个使用CMD来获得SSID的方法 C#本身是没有获得WINDOWS网路信息的能力,必须要用系统API,WMI什么的&…...

【Docker】快速部署 Nacos 注册中心
【Docker】快速部署 Nacos 注册中心 引言 Nacos 注册中心是一个用于服务发现和配置管理的开源项目。提供了动态服务发现、服务健康检查、动态配置管理和服务管理等功能,帮助开发者更轻松地构建微服务架构。 仓库地址 https://github.com/alibaba/nacos 步骤 拉取…...

OpenCV:闭运算
目录 1. 简述 2. 用膨胀和腐蚀实现闭运算 2.1 代码示例 2.2 运行结果 3. 闭运算接口 3.1 参数详解 3.2 代码示例 3.3 运行结果 4. 闭运算的应用场景 5. 注意事项 相关阅读 OpenCV:图像的腐蚀与膨胀-CSDN博客 OpenCV:开运算-CSDN博客 1. 简述…...
Python | Pytorch | Tensor知识点总结
如是我闻: Tensor 是我们接触Pytorch了解到的第一个概念,这里是一个关于 PyTorch Tensor 主题的知识点总结,涵盖了 Tensor 的基本概念、创建方式、运算操作、梯度计算和 GPU 加速等内容。 1. Tensor 基本概念 Tensor 是 PyTorch 的核心数据结…...

aws(学习笔记第二十六课) 使用AWS Elastic Beanstalk
aws(学习笔记第二十六课) 使用aws Elastic Beanstalk 学习内容: AWS Elastic Beanstalk整体架构AWS Elastic Beanstalk的hands onAWS Elastic Beanstalk部署node.js程序包练习使用AWS Elastic Beanstalk的ebcli 1. AWS Elastic Beanstalk整体架构 官方的guide AWS…...

《OpenCV》——图像透视转换
图像透视转换简介 在 OpenCV 里,图像透视转换属于重要的几何变换,也被叫做投影变换。下面从原理、实现步骤、相关函数和应用场景几个方面为你详细介绍。 原理 实现步骤 选取对应点:要在源图像和目标图像上分别找出至少四个对应的点。这些对…...
9 点结构模块(point.rs)
一、point.rs源码 use super::UnknownUnit; use crate::approxeq::ApproxEq; use crate::approxord::{max, min}; use crate::length::Length; use crate::num::*; use crate::scale::Scale; use crate::size::{Size2D, Size3D}; use crate::vector::{vec2, vec3, Vector2D, V…...

Java线程认识和Object的一些方法ObjectMonitor
专栏系列文章地址:https://blog.csdn.net/qq_26437925/article/details/145290162 本文目标: 要对Java线程有整体了解,深入认识到里面的一些方法和Object对象方法的区别。认识到Java对象的ObjectMonitor,这有助于后面的Synchron…...
【高等数学】贝塞尔函数
贝塞尔函数(Bessel functions)是数学中一类重要的特殊函数,通常用于解决涉及圆对称或球对称的微分方程。它们在物理学、工程学、天文学等多个领域都有广泛的应用,例如在波动方程、热传导方程、电磁波传播等问题中。 贝塞尔函数的…...

99.20 金融难点通俗解释:中药配方比喻马科维茨资产组合模型(MPT)
目录 0. 承前1. 核心知识点拆解2. 中药搭配比喻方案分析2.1 比喻的合理性 3. 通俗易懂的解释3.1 以中药房为例3.2 配方原理 4. 实际应用举例4.1 基础配方示例4.2 效果说明 5. 注意事项5.1 个性化配置5.2 定期调整 6. 总结7. 代码实现 0. 承前 本文主旨: 本文通过中…...
实现使用K210单片机进行猫脸检测,并在检测到猫脸覆盖屏幕50%以上时执行特定操作
要实现使用K210单片机进行猫脸检测,并在检测到猫脸覆盖屏幕50%以上时执行特定操作,以及通过WiFi上传图片到微信小程序,并在微信小程序中上传图片到开发板进行训练,可以按照以下步骤进行: 1. 硬件连接 确保K210开发板…...

小程序设计和开发:如何研究同类型小程序的优点和不足。
一、确定研究目标和范围 明确研究目的 在开始研究同类型小程序之前,首先需要明确研究的目的。是为了改进自己的小程序设计和开发,还是为了了解市场趋势和用户需求?不同的研究目的会影响研究的方法和重点。例如,如果研究目的是为了…...

tiktok 国际版抖抖♬♬ X-Bogus参数算法逆向分析
加密请求参数得到乱码,最终得到X-Bogus...
Redis 基础命令
1. redis 命令官网 https://redis.io/docs/latest/commands/ 2. 在 redis-cli 中使用 help 命令 # 查看 help string 基础命令 keys * # * 代表通配符set key value # 设置键值对del key # 删除键expire key 时间 # 给键设置时间 # -2 代表时间到期了, -1 代表…...

深入解析Python机器学习库Scikit-Learn的应用实例
深入解析Python机器学习库Scikit-Learn的应用实例 随着人工智能和数据科学领域的迅速发展,机器学习成为了当下最炙手可热的技术之一。而在机器学习领域,Python作为一种功能强大且易于上手的编程语言,拥有庞大的生态系统和丰富的机器学习库。其…...

专业的定制版软件,一键操作,无限使用
今天给大家介绍一个专业的PDF转word的小软件,软件只有5.5M。非常小,而且没有文档大小的限制,可以随意使用。 PDFtu PDF转word 软件第一次使用需要安装一下。 安装好之后,我们就能在桌面找到对应的图标,打开就能直接使…...

小程序-基础加强
前言 这一节把基础加强讲完 1. 导入需要用到的小程序项目 2. 初步安装和使用vant组件库 这里还可以扫描二维码 其中步骤四没什么用 右键选择最后一个 在开始之前,我们的项目根目录得有package.json 没有的话,我们就初始化一个 但是我们没有npm这个…...
pytorch实现基于Word2Vec的词嵌入
PyTorch 实现 Word2Vec(Skip-gram 模型) 的完整代码,使用 中文语料 进行训练,包括数据预处理、模型定义、训练和测试。 1. 主要特点 支持中文数据,基于 jieba 进行分词 使用 Skip-gram 进行训练,适用于小数…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...

论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
智能AI电话机器人系统的识别能力现状与发展水平
一、引言 随着人工智能技术的飞速发展,AI电话机器人系统已经从简单的自动应答工具演变为具备复杂交互能力的智能助手。这类系统结合了语音识别、自然语言处理、情感计算和机器学习等多项前沿技术,在客户服务、营销推广、信息查询等领域发挥着越来越重要…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...