【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秒 - 主线程接收端被当了一个迭代器来使用(因为实现了
iteratortrait),这样就不需要显式调用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 进行训练,适用于小数…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地
借阿里云中企出海大会的东风,以**「云启出海,智联未来|打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办,现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明
AI 领域的快速发展正在催生一个新时代,智能代理(agents)不再是孤立的个体,而是能够像一个数字团队一样协作。然而,当前 AI 生态系统的碎片化阻碍了这一愿景的实现,导致了“AI 巴别塔问题”——不同代理之间…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
PAN/FPN
import torch import torch.nn as nn import torch.nn.functional as F import mathclass LowResQueryHighResKVAttention(nn.Module):"""方案 1: 低分辨率特征 (Query) 查询高分辨率特征 (Key, Value).输出分辨率与低分辨率输入相同。"""def __…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
Ubuntu系统复制(U盘-电脑硬盘)
所需环境 电脑自带硬盘:1块 (1T) U盘1:Ubuntu系统引导盘(用于“U盘2”复制到“电脑自带硬盘”) U盘2:Ubuntu系统盘(1T,用于被复制) !!!建议“电脑…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
