研读Rust圣经解析——Rust learn-13(并发)

news2024/11/16 11:28:14

研读Rust圣经解析——Rust learn-13(并发)

  • 并发
    • 创建新线程
    • 使用 join 等待所有线程结束
    • 线程获取环境所有权
    • 通过消息传递传送数据
      • 创建通道
      • 发送|接收消息
      • 隐式调用recv
    • 共享状态并发
    • 通过使用互斥器Mutex
      • 创建Mutex
      • 共享Mutex
      • `Arc<T>`原子引用计数
    • 使用 Sync 和 Send trait 的可扩展并发
      • 通过Send允许在线程间转移所有权
      • Sync 允许多线程访问
      • 注意点:手动实现 Send 和 Sync 是不安全的

并发

并发编程(Concurrent programming),代表程序的不同部分相互独立的执行,而 并行编程(parallel programming)代表程序不同部分于同时执行,这两个概念随着计算机越来越多的利用多处理器的优势时显得愈发重要

已执行程序的代码在一个 进程(process)中运行,操作系统则会负责管理多个进程。在程序内部,也可以拥有多个同时运行的独立部分。这些运行这些独立部分的功能被称为 线程(threads)

创建新线程

我们可以通过spawn方法创建新线程,因为所需要的类型是FnOnce,所以我们可以直接传一个闭包进去

use std::thread;

fn main() {
    thread::spawn(|| {
        println!("new thread");
    });

    println!("origin thread");
}

使用 join 等待所有线程结束

join方法帮助我们阻塞住以保证线程执行结束,保证线程运行,因为我们不能保证线程是合适运行的也不能保证其运行顺序

use std::thread;

fn main() {
    let t1 = thread::spawn(|| {
        println!("new thread");
    });

    println!("origin thread");
    t1.join();
    println!("finish");
}

线程获取环境所有权

因为我们的线程常和闭包一起使用,所以也自然产生通过move关键字获取环境中取得的值的所有权并将这些值的所有权从一个线程传送到另一个线程

如下,这段程序是有问题的,在线程中并不能打印x的值,因为x的所有权还在main线程,所以我们应该通过使用move转移所有权

use std::thread;

fn main() {
    let x = 5;
    let t1 = thread::spawn(|| {
        println!("new thread");
        println!("{}", x);
    });

    println!("origin thread");
    t1.join();
    println!("finish");
}

修改:

use std::thread;

fn main() {
    let x = 5;
    let t1 = thread::spawn(move || {
        println!("new thread");
        println!("{}", x);
    });

    println!("origin thread");
    t1.join();
    println!("finish");
}

通过消息传递传送数据

一个日益流行的确保安全并发的方式是 消息传递(message passing),这里线程或 actor 通过发送包含数据的消息来相互沟通。为了实现消息传递并发,Rust 标准库提供了一个 信道(channel)实现。信道是一个通用编程概念,表示数据从一个线程发送到另一个线程。
在这里插入图片描述

创建通道

我们需要引入标准库中的sync中mpsc,使用channel方法构建一个通道

use std::thread;
use std::sync::mpsc;

fn main() {
    let (sender, getter) = mpsc::channel();
}

发送|接收消息

发送:send方法,返回一个 Result<T, E> 类型,所以如果接收端已经被丢弃了,将没有发送值的目标,所以发送操作会返回错误
接受:recv方法,会阻塞主线程执行直到从信道中接收一个值。一旦发送了一个值,recv 会在一个 Result<T, E> 中返回它。当信道发送端关闭,recv 会返回一个错误表明不会再有新的值到来了。

use std::thread;
use std::sync::mpsc;

fn main() {
    let (sender, getter) = mpsc::channel();
    let msg = String::from("nihao");
    sender.send(msg).unwrap_or(());
    let t1 = thread::spawn(move||{
        let g_msg = getter.recv().unwrap();
        println!("{}", g_msg);
    });
}

try_recv:不会阻塞,相反它立刻返回一个 Result<T, E>:Ok 值包含可用的信息,而 Err 值代表此时没有任何消息。如果线程在等待消息过程中还有其他工作时使用 try_recv 很有用:可以编写一个循环来频繁调用 try_recv,在有可用消息时进行处理,其余时候则处理一会其他工作直到再次检查。

隐式调用recv

不再显式调用 recv 函数:而是将 rx 当作一个迭代器。对于每一个接收到的值,我们将其打印出来。当信道被关闭时,迭代器也将结束。

for received in rx {
        println!("Got: {}", received);
    }

共享状态并发

另一种方式是让多个线程拥有相同的共享数据

在某种程度上,任何编程语言中的信道都类似于单所有权,因为一旦将一个值传送到信道中,将无法再使用这个值。共享内存类似于多所有权:多个线程可以同时访问相同的内存位置。

通过使用互斥器Mutex

互斥器(mutex)是 mutual exclusion 的缩写,也就是说,任意时刻,其只允许一个线程访问某些数据。为了访问互斥器中的数据,线程首先需要通过获取互斥器的 锁(lock)来表明其希望访问数据。锁是一个作为互斥器一部分的数据结构,它记录谁有数据的排他访问权。因此,我们描述互斥器为通过锁系统 保护(guarding)其数据。

所以我们的步骤:

  1. 在使用数据之前尝试获取锁。
  2. 处理完被互斥器所保护的数据之后,必须解锁数据,这样其他线程才能够获取锁。

正确的管理互斥器异常复杂,这也是许多人之所以热衷于信道的原因。然而,在 Rust 中,得益于类型系统和所有权,我们不会在锁和解锁上出错。

创建Mutex

let m = Mutex::new(0);

共享Mutex

在这里我们可以通过使用lock获取锁,然后通过解引用对值进行修改

use std::thread;
use std::sync::{mpsc, Mutex};

fn main() {
    let m = Mutex::new(0);
    {
        let mut num = m.lock().unwrap();
        *num = 6;
    }

    println!("{:?}", m);

Arc<T>原子引用计数

类似于Rc<T>,但是Arc具备原子性,安全的应用于并发环境,通过使用Arc可以安全的在线程间共享值

use std::thread;
use std::sync::{Arc, mpsc, Mutex};

fn main() {
    let m = Arc::new(Mutex::new(0));
    let counter = Arc::clone(&m);
    let handle = thread::spawn(move || {
        let mut lock = counter.lock().unwrap();
        *lock = 100;
    });

    handle.join().unwrap();
    println!("{:?}", *m.lock().unwrap());
}

使用 Sync 和 Send trait 的可扩展并发

Rust 的并发模型中一个有趣的方面是:语言本身对并发知之 甚少。我们之前讨论的几乎所有内容,都属于标准库,而不是语言本身的内容。由于不需要语言提供并发相关的基础设施,并发方案不受标准库或语言所限:我们可以编写自己的或使用别人编写的并发功能。

然而有两个并发概念是内嵌于语言中的:std::marker 中的 SyncSend trait

通过Send允许在线程间转移所有权

  • 只要实现Send trait类型的值就能将所有权在线程间传送
  • 几乎所有Rust类型都是Send
  • Rc<T>没有实现Send
  • 裸指针不是Send

Sync 允许多线程访问

  • Sync 标记 trait 表明一个实现了 Sync 的类型可以安全的在多个线程中拥有其值的引用(对于任意类型 T,如果 &T(T 的不可变引用)是 Send 的话 T 就是 Sync 的)
  • 基本类型都是Sync
  • Rc<T>不是Sync

注意点:手动实现 Send 和 Sync 是不安全的

通常并不需要手动实现 Send 和 Sync trait,因为由 Send 和 Sync 的类型组成的类型,自动就是 Send 和 Sync 的。因为他们是标记 trait,甚至都不需要实现任何方法。他们只是用来加强并发相关的不可变性的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/464008.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

top命令学习

文章目录 一、top命令回显信息含义1、第一行2、第二行3、第三行4、第四行5、第五行6、第六行进程信息 二、top简单交互1、按数字“1”&#xff0c;显示列出所有cpu的信息2、按“M”&#xff0c;按内存使用率从大到小排序3、按“P”&#xff0c;按CPU使用率从大到小排序 一、top…

深度学习基础知识-感知机+神经网络的学习

参考书籍&#xff1a;&#xff08;找不到资源可以后台私信我&#xff09; 《深度学习入门&#xff1a;基于Python的理论与实现 (斋藤康毅)》 《Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow, 2nd Edition (Aurelien Geron [Gron, Aurlien])》 机器学习…

(转)mysql数据库安装指南

如果你的电脑是mac&#xff0c;参考社群会员 奔跑的土豆 的分享&#xff1a; https://http://zhuanlan.zhihu.com/p/37942063232 赞同 162 评论文章 如果你的电脑是windows&#xff0c;参考下面的安装步骤。 一、下载mysql数据库 进入MySQL官方网站&#xff08;MySQL Co…

ARM Cortex-R52 通用中断控制器GIC:Generic Interrupt Controller(一)

ARM Cortex-R52 GIC:Generic Interrupt Controller 前言&#xff1a;名词解释 英文缩写英文全称&#xff08;中文释义&#xff09;GICgeneral interrupt controllerITSInterrupt Translation Service:用来解析中断SPIShared Peripheral InterruptsPPIPrivate peripheral inte…

BM40-重建二叉树

题目 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出如下图所示。 提示: 1.vin.length pre.length 2.pre 和 vin 均无重复…

超算云服务深度学习环境配置及使用方法

目录 一、环境配置 1. 通过SSH连接服务器 2. 查看服务器已安装模块 3. 调用Anaconda模块 4. 创建Python3.7的虚拟环境&#xff08;不是必须。不需要的话可以使用默认安装的环境&#xff09; 5. 虚拟环境下安装CUDA11.6Pytorch1.12.1 二、使用方法 1、提交作业 2、其他…

CKA证书模拟考试24道题

CKA证书模拟24道题-题解 快捷别名 alias kkubectl # will already be pre-configured export do"--dry-runclient -o yaml" # k create deploy nginx --imagenginx $do export now"--force --grace-period 0" # k delete p…

FPGA学习_01_基础知识(有点劝退,心灵弱小者勿入)

有些人喜欢直接拿开发板看教程开干&#xff0c;我认为了解点历史发展没什么坏处&#xff0c;一些FPGA的基础知识也是同样重要的。 1.1. FPGA的主要厂商 XILINX 占据FPGA绝大部分的市场份额 ALTERA 被 INTEL 167亿美元收购 改名为INTEL LATTICE 被神秘的中国公…

成就客户 | 企业如何培养“数据文化”?Smartbi教你3个步骤

随着数字化浪潮的发展&#xff0c;越来越多企业在实际工作中通过采用BI等各种数据处理工具提升工作效率。诚然&#xff0c;BI 工具可以帮助员工更好地理解和分析数据&#xff0c;从而发现业务中的机遇和挑战&#xff0c;然而如果仅仅只是提供工具和技术&#xff0c;而不重视培养…

浅谈“孔乙己的长衫“是脱不下来还是难脱下?

名人说&#xff1a;往者不可谏&#xff0c;来者犹可追。——《论语微子篇》 创作者&#xff1a;Code_流苏(CSDN) ★温馨提示&#xff1a;以下仅代表个人观点&#xff0c;不代表其它任何人看法。 目录 〇、缘由一、社会对于学历和职业之间的关系认知是怎样的&#xff1f;二、学…

密歇根大学Python系列之二:Python 编程进阶

Python如今无疑是全球最受欢迎的编程语言。它最大的好处&#xff0c;就是让越来越多的人通过它加入了编程的世界。学习Python是个好主意。无论你是一个初学者还是C或Java专家&#xff0c;都无需担心其派不上用场。 Paul Resnick 教授是密歇根大学迈克尔科恩学院的信息学教授&a…

解决软件项目冲突的5个重点

1、针对人员冲突管理 信任和沟通是解决人员冲突的关键。常见的人员冲突多表现为不信任和沟通不畅。 企业高层需要对项目经理充分信任和授权&#xff0c;以充分发挥项目经理的能力。项目经理对项目至关重要&#xff0c;如果项目经理频繁换人&#xff0c;高层领导变动&#xff0c…

云原生-k8s核心概念(pod,deploy,service,ingress,configmap,volume)

Gitee-k8s学习 云原生实战-kubernetes核心实战 namespace Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离 Pod Pod可以认为是容器的封装&#xff0c;一个Pod中可以存在一个或者多个容器。 De…

C#开发的OpenRA的游戏用户的添加

C#开发的OpenRA的游戏用户的添加 OpenRA游戏前面在游戏开始的按钮的界面, 可以看到可以添加游戏用户,小规模战斗的界在,就是默认两个用户, 一个是玩家,一个是电脑的AI, 如果感觉少了,可以添加多几个电脑AI,这样做也是可以的。 不过在代码里是怎么样实现添加用户的呢…

word表格

新建&#xff08;修改&#xff09;“表格”样式 新建和修改样式的设置差不多&#xff0c;这里放在一起介绍 设置样式时&#xff0c;注意按图中的步骤设置&#xff0c;以免导致格式的应用出错&#xff0c;这里分四步&#xff1a; 格式应用于 “整个表格”&#xff1a;“字体”…

启英泰伦智能语音芯片在语音控制吸顶灯上的应用解决方案

随着智能控制技术的不断发展&#xff0c;人们对于家用电器的功能需求越来越多&#xff0c;智能吸顶灯是一种常见的照明设备&#xff0c;通常被安装在室内房顶上面&#xff0c;除了具有传统吸顶灯的照明功能外&#xff0c;还添加了智能控制和自动化功能&#xff0c;如远程控制、…

python Import Error: cannot import name SystemRandom

目录 一、前言二、解决方法三、改名之后带来的问题解决四、总结 一、前言 今天运行项目里面的文件&#xff0c;发现我简单的调试都不行&#xff0c;导入包就是不行&#xff0c;但是我新建一个窗口&#xff0c;把运行文件复制到另一个目录下就可以&#xff0c;就很奇怪。 报错信…

速卖通正式推出全托管,卖家竞争进入新阶段

全托管来了&#xff0c;卖家就能安心做甩手掌柜吗&#xff1f; 正式推出全托管 显而易见&#xff0c;越来越多的平台正在转向全托管模式。 近日&#xff0c;速卖通在2023年度商家峰会上&#xff0c;正式推出了全托管服务模式。官方表示&#xff0c;托管是对速卖通平台商家服…

市级大数据中心大数据资源平台概要设计方案(ppt可编辑)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 大数据管理中心发展背景 为建设卓越全球城市&#xff0c;实现政府治理能力现代化目标&#xff0c;由市大数据中心牵头&#xff0c;在政务公共数据管理和互联网政务服务方面…

一场没有英伟达/高通的上海车展

两年一度的上海国际车展&#xff0c;在2023年迎来「质」的变化。一方面&#xff0c;电动化浪潮已成定局&#xff0c;无论是传统自主品牌&#xff0c;还是合资品牌&#xff0c;新能源车型成为展区的主角。另一方面&#xff0c;零部件供应商的合纵连横&#xff0c;中外合作&#…