当前位置: 首页 > news >正文

Rust所有权和Move关键字使用和含义讲解,以及Arc和Mutex使用

Rust 所有权规则

一个值只能被一个变量所拥有,这个变量被称为所有者。
一个值同一时刻只能有一个所有者,也就是说不能有两个变量拥有相同的值。所以对应变量赋值、参数传递、函数返回等行为,旧的所有者会把值的所有权转移给新的所有者,以便保证单一所有者的约束。
当所有者离开作用域,其拥有的值被丢弃,内存得到释放。
这三条规则很好理解,核心就是保证单一所有权。其中第二条规则讲的所有权转移是 Move 语义,Rust 从 C++ 那里学习和借鉴了这个概念。

第三条规则中的作用域(scope)指一个代码块(block),在 Rust 中,一对花括号括起来的代码区就是一个作用域。举个例子,如果一个变量被定义在 if {} 内,那么 if 语句结束,这个变量的作用域就结束了,其值会被丢弃;同样的,函数里定义的变量,在离开函数时会被丢弃。

所有权规则,解决了谁真正拥有数据的生杀大权问题,让堆上数据的多重引用不复存在,这是它最大的优势。 但是,它也有一个缺点,就是每次赋值、参数传递、函数返回等行为,都会导致旧的所有者把值的所有权转移给新的所有者,这会导致一些性能上的问题。

Move关键字

Rust 是一门以安全性著称的系统编程语言,它允许程序员高效地进行并发编程。在 Rust 中,线程是一种重要的并发原语,通过标准库提供的 std::thread 模块,我们可以轻松地创建和管理线程。而 Move 闭包是一种特殊的闭包,它可以在创建时传递外部变量的所有权,使得在多线程环境中传递数据更加灵活和高效。

Rust 中的线程

在 Rust 中,线程是一种独立的执行流,它允许程序在不同的执行路径上同时运行。Rust 的线程模型采用了“共享状态,可变状态”(Shared State, Mutable State)的方式,这意味着多个线程可以访问同一个数据,但需要通过锁(Lock)来保证数据的安全性。

创建线程:在 Rust 中,我们可以使用 std::thread::spawn 函数来创建一个新的线程。下面是一个简单的例子:

use std::thread;fn main() {let handle = thread::spawn(|| {println!("Hello from the new thread!");});handle.join().unwrap();
}

在上述示例中,我们调用 thread::spawn 函数创建了一个新的线程,并在该线程中打印一条信息。注意,thread::spawn 函数接受一个闭包作为参数,闭包中的代码会在新线程中执行。

线程间通信
在多线程编程中,线程间通信是一个重要的问题。在 Rust 中,我们可以使用 std::sync 模块提供的同步原语来实现线程间的安全通信。常见的同步原语包括 Mutex(互斥锁)和 Arc(原子引用计数)等。

下面是一个使用 Mutex 实现线程安全计数的例子:

use std::sync::{Arc, Mutex};
use std::thread;fn main() {let counter = Arc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..10 {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());
}

在上述示例中,我们创建了一个 Mutex 来包装计数器变量 counter,以实现线程安全的计数。在每个线程中,我们通过 counter.lock().unwrap() 获取 Mutex 的锁,然后通过 *num += 1 修改计数器的值。在修改完成后,锁会自动释放。

Move 闭包

Rust 中的闭包有三种形式:Fn、FnMut 和 FnOnce。其中,FnOnce 是最特殊的一种,它可以消耗捕获的变量,并且只能被调用一次。这种特性使得 FnOnce 闭包可以在创建时携带外部变量的所有权,并在闭包内使用这些变量。

在线程中使用 Move 闭包:
在多线程编程中,有时我们希望在线程创建时将一些数据传递给新线程,并且希望新线程拥有这些数据的所有权,这时就可以使用 Move 闭包。

下面是一个使用 Move 闭包的例子:

use std::thread;fn main() {let data = vec![1, 2, 3, 4, 5];let handle = thread::spawn(move || {for num in data {println!("Number: {}", num);}});handle.join().unwrap();
}

在上述示例中,我们创建了一个 data 向量,并在 thread::spawn 函数中使用 move 关键字将 data 向量的所有权转移给了新线程。这样,新线程就拥有了 data 向量的所有权,可以在闭包中访问和使用它。

需要注意的是,使用 Move 闭包时要特别小心数据的所有权转移。如果在闭包外部继续使用了数据,可能会导致编译错误或运行时错误: 

使用 Arc 和 Move 闭包

在某些情况下,我们希望在多个线程中共享数据,并且某些线程需要拥有数据的所有权。这时,可以结合使用 Arc 和 Move 闭包来实现。

下面是一个使用 Arc 和 Move 闭包的例子:

use std::sync::{Arc, Mutex};
use std::thread;fn main() {// creat arc indexlet data = Arc::new(Mutex::new(vec![1, 2, 3, 4]));let mut task_list = vec![];for i in 0..4 {// clone current data index, to move it into threadlet cur = Arc::clone(&data);task_list.push(thread::spawn(move || {// get lock and reset datalet mut lock = cur.lock().unwrap();lock[i] += 100;}));}// join handlerfor l in task_list {l.join().unwrap();}println!("Result: {:?}", data.lock());
}

在上述示例中,我们创建了一个 data 向量,并将它包装在 Arc 和 Mutex 中以实现线程安全共享。然后,我们使用 map 方法创建了5个线程,并在每个线程中修改 data 向量的一个元素。通过使用 Move 闭包和 Arc,每个线程都拥有了 data 向量的所有权,可以在闭包中修改它。

多线程与 Move 闭包的应用场景

多线程和 Move 闭包在 Rust 中有着广泛的应用场景,尤其是在并发处理和性能优化方面。以下是一些常见的应用场景:

并行计算:多线程可以同时执行独立的任务,提高计算速度和性能。
并发服务器:服务器需要同时处理多个客户端请求,多线程可以使服务器更高效地处理并发请求。
数据处理:在数据处理任务中,多线程可以同时处理不同的数据块,加速数据处理过程。

相关文章:

Rust所有权和Move关键字使用和含义讲解,以及Arc和Mutex使用

Rust 所有权规则 一个值只能被一个变量所拥有,这个变量被称为所有者。 一个值同一时刻只能有一个所有者,也就是说不能有两个变量拥有相同的值。所以对应变量赋值、参数传递、函数返回等行为,旧的所有者会把值的所有权转移给新的所有者&#…...

【YOLOV5 入门】——构建自己的数据集模型训练模型检验

一、准备工作 1、数据收集 图片类型数据不用多说;视频类型数据利用opencv进行抽帧保存为一张张图片,这里选取30s的名侦探柯南片段进行试验,确保环境解释器下安装了opencv(我使用的是另一个虚拟环境): im…...

MacBook 访达使用技巧【mac 入门】

快捷键 打开访达搜索窗口默认快捷键【⌥ ⌘ 空格键】可以在键盘【系统偏好设置 -> 键盘->快捷键->聚焦】修改 但是我不会去修改它,因为我不常用访达的搜索窗口,更多的是想快速打开访达文件夹窗口,可以通过第三方软件定义访达的快…...

常见溯源,反溯源,判断蜜罐手段

常见溯源,反溯源,判断蜜罐手段 1.溯源手段2.反溯源手段3.如何判断蜜罐🍯4.案例:MySQL读文件蜜罐 1.溯源手段 IP地址追踪:通过IP地址追踪可以确定攻击者的地理位置和ISP信息等;通过攻击IP历史解析记录/域名…...

蓝桥杯刷题-09-三国游戏-贪心⭐⭐⭐

蓝桥杯2023年第十四届省赛真题-三国游戏 小蓝正在玩一款游戏。游戏中魏蜀吴三个国家各自拥有一定数量的士兵X, Y, Z (一开始可以认为都为 0 )。游戏有 n 个可能会发生的事件,每个事件之间相互独立且最多只会发生一次,当第 i 个事件发生时会分别让 X, Y,…...

Windows编译运行TensorRT-YOLOv9 (C++)

Windows编译运行yolov9-bytetrack-tensorrt(C) 1 基础环境2 编译yolov9-bytetrack-tensorrt(1)下载yolov9-bytetrack-tensorrt源码(2)修改CMakeLists.txt(3)CMake编译 3 yolov9模型转…...

.NET 设计模式—简单工厂(Simple Factory Pattern)

简介 简单工厂模式(Simple Factory Pattern)属于类的创建型模式,又叫静态工厂方法模式(Static FactoryMethod Pattern),是通过一个工厂类来创建对象,根据不同的参数或条件返回相应的对象实例。这种模式隐藏…...

聊聊Linux内核中内存模型

介绍 在Linux中二进制的程序从磁盘加载到内存,运行起来后用户态是使用pid来唯一标识进程,对于内核都是以task_struct表示。二进制程序中的数据段、代码段、堆都能提现在task_struct中。每一个进程都有自己的虚拟地址空间,虚拟地址空间包含几…...

docker自动化部署示例

前提 安装docker 、 docker-cpmpose、git、打包环境(如meaven、jdk、node等) 原理 git Dockerfile docker-compose 获取源码(代码仓库)获取可运行程序的镜像(docker)将打包后的程序放入镜像内&#xf…...

Redis精品案例解析:Redis实现持久化主要有两种方式

Redis实现持久化主要有两种方式:RDB(Redis DataBase)和AOF(Append Only File)。这两种方式各有优缺点,适用于不同的使用场景。 1. RDB持久化 RDB持久化是通过创建一个二进制的dump文件来保存当前Redis数据…...

Python | Leetcode Python题解之第14题最长公共前缀

题目: 题解: class Solution:def longestCommonPrefix(self, strs: List[str]) -> str:def isCommonPrefix(length):str0, count strs[0][:length], len(strs)return all(strs[i][:length] str0 for i in range(1, count))if not strs:return &quo…...

烧坏两块单片机,不知道原因?

没有看你的原理图,以下是造成烧毁芯片的几个环节: 1. 最大的可能性是你的单片机电机控制输出与电机驱动电路没有隔离。 我的经验,使用STM32控制电机,无论是直流电机脉宽调制,还是步进电机控制,控制电路与…...

SV学习笔记(八)

文章目录 SV入门练习基本数据类型字符串类型数组类型接口的定义与例化类的封装类的继承package的使用随机约束线程的同步线程的控制虚方法方法(任务与函数)SV用于设计 参考资料 SV入门练习 基本数据类型 有符号无符号、四状态双状态、枚举类型、结构体…...

Java反射常用方法

反射 作用: 对于任意一个对象,把对象所有的字段名和值,保存到文件中去利用反射动态的创造对象和运行方法 1. 获取字节码文件对象 方法描述Class.forName(String)通过类的全限定名字符串获取字节码文件对象。类字面量直接使用类的字面量获…...

go语言实现无头单向链表

什么是无头单向链表 无头单向链表是一种线性数据结构,它的每个元素都是一个节点,每个节点都有一个指向下一个节点的指针。"无头"意味着这个链表没有一个特殊的头节点,链表的第一个节点就是链表的头。 优点: 动态大小&…...

SpringBoot快速入门笔记(5)

文章目录 一、elemetnUI1、main.js2、App.vue3、fontAwesome 一、elemetnUI 开源前端框架,安装 npm i element-ui -S 建议查看官方文档 Element组件,这里是Vue2搭配elementUI,如果是vue3就搭配elementPlus,这里初学就以Vue2为例子…...

solidity(3)

地址类型 pragma solidity ^0.8.0;contract AddressExample {// 地址address public _address 0x7A58c0Be72BE218B41C608b7Fe7C5bB630736C71;address payable public _address1 payable(_address); // payable address,可以转账、查余额// 地址类型的成员uint256…...

笔记 | 编译原理L1

重点关注过程式程序设计语言编译程序的构造原理和技术 1 程序设计语言 1.1 依据不同范型 过程式(Procedural programming languages–imperative)函数式(Functional programming languages–declarative)逻辑式(Logical programming languages–declarative)对象式(Object-or…...

k8s存储卷 PV与PVC 理论学习

介绍 存储的管理是一个与计算实例的管理完全不同的问题。PersistentVolume 子系统为用户和管理员提供了一组 API,将存储如何制备的细节从其如何被使用中抽象出来。为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 Persistent…...

【WPF应用32】WPF中的DataGrid控件详解与示例

在WPF(Windows Presentation Foundation)开发中,DataGrid控件是一个强大的数据绑定工具,它以表格的形式展示数据,并支持复杂的编辑、排序、过滤和分组等操作。在本文中,我们将详细介绍DataGrid控件的功能、…...

使用VSCode开发Django指南

使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

PL0语法,分析器实现!

简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

爬虫基础学习day2

# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版,柱状图PPT模版,线状图PPT模版,折线图PPT模版,饼状图PPT模版,雷达图PPT模版,树状图PPT模版 图表类系列各种样式PPT模版分享:图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈

在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...

小木的算法日记-多叉树的递归/层序遍历

🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...