【Rust 指南】并发编程|无畏并发的原因

news2024/11/16 20:48:23

在这里插入图片描述

文章目录

  •   前言
  • 1、线程
    • 1.1、通过 spawn 创建新线程
    • 1.2、join 方法
  • 2、move 强制所有权迁移
  • 3、使用消息传递跨线程传递数据
    • 3.1、Send 方法
    • 3.2 、Sync 方法

  前言

   安全高效的处理并发是 Rust 诞生的目的之一,主要解决的是服务器高负载承受能力。
并发concurrent)的概念是指程序不同的部分独立执行,这与并行parallel)的概念容易混淆,并行强调的是"同时执行",而并发往往会造成并行。

Rust 无畏并发:允许你编写没有细微 Bug 的代码,并在不引入新 Bug 的情况下易于重构


1、线程

线程(thread)是一个程序中独立运行的一个部分,不同于进程(process)的地方是线程是程序以内的概念,程序往往是在一个进程中执行的。

在有操作系统的环境中进程往往被交替地调度得以执行,线程则在进程以内由程序进行调度。

由于线程并发很有可能出现并行的情况,所以在并行中可能遇到的死锁、延宕错误常出现于含有并发机制的程序。

为了解决这些问题,很多其它语言(如 Java、C#)采用特殊的运行时(runtime)软件来协调资源,但这样无疑极大地降低了程序的执行效率。
C/C++ 语言在操作系统的最底层也支持多线程,且语言本身以及其编译器不具备侦察和避免并行错误的能力,这对于开发者来说压力很大,开发者需要花费大量的精力避免发生错误。

Rust 不依靠运行时环境,这一点像 C/C++ 一样,但 Rust 在语言本身就设计了包括所有权机制在内的手段来尽可能地把最常见的错误消灭在编译阶段,这一点其他语言不具备。
但这不意味着我们编程的时候可以不小心,迄今为止由于并发造成的问题还没有在公共范围内得到完全解决,仍有可能出现错误,并发编程时要尽量小心!

1.1、通过 spawn 创建新线程

使用 thread::spawn 函数可以创建新线程:

  • 参数:一个闭包(在新线程里运行的代码)
  • 示例:
use std::{thread, time::Duration};

fn main() {
    // 新线程
    thread::spawn(|| {
        for i in 1..10{
            println!("hi number {} from the spawn thread!",i);
            thread::sleep(Duration::from_millis(1));
        }
    });
    // 主线程
    for i in 1..5{
        println!("hi number {} from the main thread!",i);
        thread::sleep(Duration::from_millis(1));
    }
}

在这里插入图片描述

这个结果在某些情况下顺序有可能变化,但总体上是这样打印出来的。
此程序有一个子线程,目的是打印 9 行文字,主线程打印 4 行文字,但很显然随着主线程的结束,spawn 线程也随之结束了,并没有完成所有打印。

1.2、join 方法

join 方法可以使子线程运行结束后再停止运行程序:

use std::{thread, time::Duration};

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10{
            println!("hi number {} from the spawn thread!",i);
            thread::sleep(Duration::from_millis(1));
        }
    });
    for i in 1..5{
        println!("hi number {} from the main thread!",i);
        thread::sleep(Duration::from_millis(20));
    }
    // 放在主线程最后
    handle.join().unwrap();
}

在这里插入图片描述

放到主线程最后,当主线程运行完毕,等子线程运行完毕,程序才结束

如果放在主线程之前,情况就会变化:

在这里插入图片描述

这里是子线程执行完毕后才执行主线程,继而程序结束

2、move 强制所有权迁移

来看看常见的问题:

use std::thread;

fn main() {
    let s = "hello";
   
    let handle = thread::spawn(|| {
        println!("{}", s);
    });

    handle.join().unwrap();
}

子线程中尝试使用当前函数的资源,这一定是错误的!因为所有权机制禁止这种危险情况的产生,它将破坏所有权机制销毁资源的一定性。

我们可以使用闭包的 move 关键字来处理:

use std::thread;

fn main() {
    let s = "hello";
    // 解决方法 move ||
    let handle = thread::spawn(move || {
        println!("{}", s);
    });

    handle.join().unwrap();
}

3、使用消息传递跨线程传递数据

消息传递是一种很流行且能保证安全并发的技术,线程通过彼此发送消息来进行通信。

Go 语言名言:不要用共享内存来通信,要用通信来共享内存

Rust 中一个实现消息传递并发的主要工具是通道channel),通道有两部分组成,一个发送者transmitter)和一个接收者receiver)。

std::sync::mpsc 包含了消息传递的方法:

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

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);
}
// 运行结果:Got: hi

子线程获得了主线程的发送者 tx,并调用了它的 send 方法发送了一个字符串,然后主线程就通过对应的接收者 rx 接收到了。

3.1、Send 方法

  • 实现Send trait的类型可在线程间转移所有权
  • Rust 中几乎所有的类型都实现了Send
    • Rc<T>没有实现Send,它只用于单线程情景
  • 任何完全由Send类型组成的类型也被标记为Send
  • 除了原始指针之外,几乎所有的基础类型都是Send

3.2 、Sync 方法

  • 实现 Sync 的类型可以安全的被多个线程引用
  • 如果 TSync,那么 &T 就是 Send
    • 引用可以被安全的送往另一个线程
  • 基础类型都是 Sync
  • 完全由 Sync 类型组成的类型也是 Sync
    • 但,Rc<T> 不是 Sync
    • RefCell<T>Cell<T>家族也不是 Sync
    • Mutex<T>Sync

最后要注意:手动来实现 SendSync 是不安全的,需要非常谨慎的使用。

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

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

相关文章

石家庄正定县恢复种植 国稻种芯·中国水稻节:河北绘就画卷

石家庄正定县恢复种植 国稻种芯中国水稻节&#xff1a;河北绘就画卷 新华社记者 杨世尧 摄 河北日报 通讯员张 晓峰 摄影报道 新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会…

MongoDB备份与恢复

MongoDB备份与恢复 文章目录MongoDB备份与恢复1.备份恢复工具2.备份工具区别3.mongoexport导出工具命令4.导出MongoDB的表4.1.创建备份的目录4.2.登录数据库4.3.查询表和表中数据4.4.导出数据为json格式4.5.导出数据为csv格式5.mongoimport导入工具5.1.恢复json格式数据5.2.登录…

Python基础-3-列表

一&#xff1a;简述 列表是由一系列按特定顺序排列的元素组成&#xff0c;可以创建包含字母表中所有字母&#xff0c;数字或家庭成员姓名的列表&#xff1b;也可以将任何东西加入列表&#xff0c;其中的元素之间可以没有任何关系。列表中通常包含了多个元素&#xff0c;因此给…

HTTPS中间人攻击实验

HTTPS中间人攻击实验 一.实验基础 1、HTTPS概述 HTTPS (全称: Hyper Text Transfer Protocol over SecureSocketLayer)&#xff0c; 是以安全为目标的HTTP通道&#xff0c;在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。 默认端口&#xff1a;443 SSLspli…

【无人机】基于拓展卡尔曼滤波时序四旋翼无人机状态跟踪附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

SpringBoot+Vue项目实现疫情期间社区出入管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

web前端期末大作业——基于Bootstrap响应式汽车经销商4S店官网21页

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

【prometheus上报和使用】

prometheus上报和使用prometheus环境搭建进行上报CountrateirateincreaseGaugehistogram分位线summaryprometheus Prometheus是由SoundCloud开发的开源监控系统&#xff0c;由GO语言编写而成&#xff0c;采用Pull的方式来获取监控信息&#xff0c;并且提供了多维度的数据模型和…

Linux-sed

sed sed是一种几乎包括所有UNIX平台&#xff08;包括Linux&#xff09;的轻量级流编辑器。sed主要用来将数据进行选取、替换、删除、新增的命令 sed [选项] ‘[动作]’ 文件名 选项&#xff1a; -n&#xff1a;一般sed命令会把所有数据都输出到屏幕&#xff0c;如果加入此选项…

vue.js毕业设计,基于vue.js前后端分离订座预约系统设计与实现(H5移动项目)

功能介绍 【后台功能】 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信息&#xff0c;支持删除 录入资讯&#xff1a;录入资讯标题、内容等信息 管理资讯&#x…

HTTP Only下的XSS攻击

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是HTTP Only下的XSS攻击。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权…

程序猿成长之路之密码学篇-密码学简介

在阅读本文前需要了解的术语&#xff1a; 授权人/非授权人&#xff1a;授权人指获取了查看数据权限的用户&#xff0c;非授权人则是指未获取到权限的用户。明文/密文&#xff1a;明文指没有加密的数据内容&#xff0c;密文是指加密后的数据内容CIA(密码学中不是美国中情局的意思…

npm 如何更新项目最新依赖包

NPM 是什么&#xff1f; Node 软件包管理器(NPM)提供了各种功能来帮助你安装和维护项目的依赖关系。 由于错误修复、新功能和其他更新&#xff0c;依赖关系可能会随着时间的推移而变得过时。你的项目依赖越多&#xff0c;就越难跟上这些更新。 老旧的软件包会对安全构成威胁&am…

USB-数据传输

一、USB编码-反向不归零编码(NRZI)位填充 规则&#xff1a;数据为0&#xff0c;电平反转&#xff0c;数据为1&#xff0c;电平不翻转;当连续出现6个相同的1穿插一个0&#xff0c;目的是为了防止连续出现多个1导致的同步漂移。 二、USB传输帧 帧是USB传输的时间单位&#xff0…

深入浅出PyTorc——进阶训练技巧

1. 自定义损失函数 1.1 以函数方式定义 手动写出损失的公式并用函数进行存储&#xff0c;方便调用。 def my_loss(output, target):loss torch.mean((output - target)**2)return loss 1.2 以类方式定义 1.2.1 损失函数的继承关系 &#xff08;1&#xff09;Loss函数部分继…

POI及EasyExcel

1.谈谈 POI 和 easyExcel 应用场景 1.将用户信息导出为excel表格&#xff08;导出数据....&#xff09;2.将Excel表中的信息录入到网站数据库&#xff08;习题上传....&#xff09; 开发中经常会设计到excel的处理&#xff0c;如导出Excel&#xff0c;导入Excel到数据库中&…

详解Spring面试IoC和AOP

Spring IOC 和 AOP 文章目录Spring IOC 和 AOP前言什么是 IoC&#xff1f;**为什么叫控制反转**不用IoC&#xff1a;所有对象开发者自己创建使用IoC&#xff1a;对象不用卡法这创建&#xff0c;而是交给Spring框架完成基于XML和基于注解基于XML&#xff1a;基于注解&#xff1a…

TeeChart Pro for .NET 2022.10.24 Crack

.NNET 的 TeeChart 图表控件提供了一个很好的通用组件套件&#xff0c;可以满足无数的图表需求&#xff0c;也针对重要的垂直领域&#xff0c;例如金融、科学和统计领域。 数据可视化 数十种完全可定制和交互式的图表类型、地图和仪表指示器&#xff0c;以及完整的功能集&#…

大一html5期末大作业 :基于html实现传统文化网页设计题材

Web前端开发技术 描述 网页设计题材&#xff0c;DIVCSS 布局制作,HTMLCSS网页设计期末课程大作业 | 国家级非遗 | 非遗文化 | 非遗网页设计 | 非遗保护 | 非遗之旅 | 非遗传承HTML期末大学生网页设计作业 HTML&#xff1a;结构 CSS&#xff1a;样式 在操作方面上运用了html5和…