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

Rust 练习册 10:多线程基础与并发安全

并发编程是现代软件开发中的重要主题,它允许程序同时执行多个任务以提高性能和响应性。Rust 通过其所有权系统和类型系统,在编译时就保证了线程安全,避免了数据竞争等常见并发问题。今天我们就来深入学习 Rust 中的多线程编程基础。

什么是多线程编程?

多线程编程允许程序同时执行多个线程,每个线程都是独立的执行路径。在 Rust 中,线程是轻量级的,由操作系统调度,可以并行执行以提高程序性能。

项目中的示例代码

让我们先看看项目中的示例代码:

use std::{thread, time::Duration};#[test]
fn it_works() {let duration = Duration::from_millis(3000);thread::spawn(move || {thread::sleep(duration);});assert_eq!(duration.as_millis(), 3000);println!("{:?}", duration);
}// fn inner_fn(vref: &mut Vec<u32>) {
//     std::thread::spawn(move || {
//         vref.push(1);
//     });
// }
#[test]
fn inner_it_works() {let mut v = vec![1, 2, 3];// inner_fn(&mut v);
}

在这个示例中,我们使用 thread::spawn 创建了一个新线程,该线程会休眠 3 秒。注意 move 关键字的使用,它将 duration 变量的所有权转移到新线程中。

被注释掉的代码展示了 Rust 如何防止数据竞争:我们不能简单地将可变引用传递给新线程,因为这会违反 Rust 的借用规则。

基本线程操作

创建线程

use std::thread;
use std::time::Duration;fn basic_thread_creation() {// 创建一个新线程let handle = thread::spawn(|| {for i in 1..10 {println!("hi number {} from the spawned 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));}// 等待新线程完成handle.join().unwrap();
}

使用 move 关键字

use std::thread;fn move_keyword_example() {let v = vec![1, 2, 3];let handle = thread::spawn(move || {println!("Here's a vector: {:?}", v);});handle.join().unwrap();
}

move 关键字将闭包环境中使用的值的所有权转移到新线程中。

线程间通信

使用通道(Channels)

use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn channel_example() {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);}
}

多生产者通道

use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn multiple_producers_example() {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);}
}

共享状态并发

使用互斥锁(Mutex)

use std::sync::{Arc, Mutex};
use std::thread;fn mutex_example() {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());
}

使用原子类型

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;fn atomic_example() {let counter = Arc::new(AtomicUsize::new(0));let mut handles = vec![];for _ in 0..10 {let counter = Arc::clone(&counter);let handle = thread::spawn(move || {counter.fetch_add(1, Ordering::SeqCst);});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {}", counter.load(Ordering::SeqCst));
}

线程安全的智能指针

Arc(原子引用计数)

use std::sync::Arc;
use std::thread;fn arc_example() {let data = Arc::new(vec![1, 2, 3, 4]);let mut handles = vec![];for i in 0..4 {let data_clone = Arc::clone(&data);let handle = thread::spawn(move || {println!("Thread {}: {:?}", i, data_clone);});handles.push(handle);}for handle in handles {handle.join().unwrap();}
}

实际应用示例

并行计算

use std::sync::{Arc, Mutex};
use std::thread;fn parallel_computation_example() {let numbers: Vec<i32> = (1..=1000).collect();let sum = Arc::new(Mutex::new(0));let mut handles = vec![];let chunk_size = numbers.len() / 4;for chunk in numbers.chunks(chunk_size) {let chunk = chunk.to_vec();let sum_clone = Arc::clone(&sum);let handle = thread::spawn(move || {let chunk_sum: i32 = chunk.iter().sum();let mut total = sum_clone.lock().unwrap();*total += chunk_sum;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Sum: {}", *sum.lock().unwrap());
}

生产者-消费者模式

use std::sync::mpsc;
use std::thread;
use std::time::Duration;fn producer_consumer_example() {let (tx, rx) = mpsc::channel();// 生产者线程let producer = thread::spawn(move || {for i in 0..10 {println!("Producing item {}", i);tx.send(i).unwrap();thread::sleep(Duration::from_millis(500));}});// 消费者线程let consumer = thread::spawn(move || {for received in rx {println!("Consuming item {}", received);thread::sleep(Duration::from_millis(750));}});producer.join().unwrap();consumer.join().unwrap();
}

错误处理与线程

处理线程中的 panic

use std::thread;fn panic_handling_example() {let handle = thread::spawn(|| {panic!("Oops!");});match handle.join() {Ok(_) => println!("Thread completed successfully"),Err(_) => println!("Thread panicked"),}
}

返回结果的线程

use std::thread;fn result_thread_example() {let handle = thread::spawn(|| -> Result<i32, &'static str> {// 一些可能失败的操作Ok(42)});match handle.join() {Ok(Ok(result)) => println!("Result: {}", result),Ok(Err(err)) => println!("Error: {}", err),Err(_) => println!("Thread panicked"),}
}

最佳实践

1. 合理使用线程

use std::thread;
use std::time::Duration;// 好的做法:为计算密集型任务使用线程
fn good_thread_usage() {let handle = thread::spawn(|| {// CPU 密集型计算let result: u128 = (1..1_000_000).map(|x| x * x).sum();result});// 在等待时做其他工作println!("Doing other work while waiting...");let result = handle.join().unwrap();println!("Result: {}", result);
}// 避免:为简单任务创建过多线程
fn avoid_excessive_threads() {// 不好的做法:为每个简单操作创建线程// let handles: Vec<_> = (0..1000)//     .map(|i| {//         thread::spawn(move || i * 2)//     })//     .collect();
}

2. 正确处理所有权

use std::sync::{Arc, Mutex};
use std::thread;fn ownership_example() {let data = Arc::new(Mutex::new(vec![1, 2, 3, 4, 5]));let mut handles = vec![];// 正确:克隆 Arc 来共享所有权for i in 0..3 {let data_clone = Arc::clone(&data);let handle = thread::spawn(move || {let mut vec = data_clone.lock().unwrap();vec.push(i);});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Final data: {:?}", *data.lock().unwrap());
}

与项目代码的深入分析

让我们回到原始项目代码,深入分析其中的概念:

use std::{thread, time::Duration};#[test]
fn it_works() {let duration = Duration::from_millis(3000);thread::spawn(move || {thread::sleep(duration);});assert_eq!(duration.as_millis(), 3000);println!("{:?}", duration);
}

这段代码展示了:

  1. 使用 move 关键字将 duration 的所有权转移到新线程
  2. 在新线程中使用 thread::sleep 模拟耗时操作
  3. 主线程继续执行而不等待子线程完成

被注释的代码揭示了 Rust 的一个重要特性:

// fn inner_fn(vref: &mut Vec<u32>) {
//     std::thread::spawn(move || {
//         vref.push(1);
//     });
// }

这段代码无法编译,因为:

  1. &mut Vec<u32> 是一个可变引用
  2. 将可变引用移动到新线程会违反 Rust 的借用规则
  3. 这会可能导致数据竞争

正确的做法是使用 Arc<Mutex<T>>

use std::sync::{Arc, Mutex};
use std::thread;fn correct_shared_mutable_state() {let mut v = vec![1, 2, 3];let shared_v = Arc::new(Mutex::new(v));let shared_v_clone = Arc::clone(&shared_v);let handle = thread::spawn(move || {let mut vec = shared_v_clone.lock().unwrap();vec.push(1);});handle.join().unwrap();println!("Vector: {:?}", *shared_v.lock().unwrap());
}

总结

Rust 的多线程编程通过其所有权系统提供了强大的安全保障:

  1. thread::spawn 创建新线程
  2. move 关键字转移所有权到新线程
  3. 通道(Channels)提供线程间安全通信
  4. MutexArc 允许安全的共享状态
  5. 原子类型提供无锁并发操作

关键要点:

  • Rust 在编译时防止数据竞争
  • 所有权系统确保线程安全
  • 通过 move 关键字明确所有权转移
  • 使用标准库提供的同步原语处理共享状态

通过合理使用这些特性,我们可以编写出既高效又安全的并发程序。

http://www.dtcms.com/a/578191.html

相关文章:

  • 电子商务网站建设评估工具办公宽带多少钱一年
  • Razor VB 变量详解
  • 输入一个故事主题,使用大语言模型生成故事视频【视频中包含大模型生成的图片、故事内容,以及音频和字幕信息】
  • 英文网站首页优化中信建设有限责任公司招投标
  • 前端浏览器设置input不记住密码、不自动填充密码,举例jquery
  • 二级域名免费申请网站环球资源网站网址
  • 网站建设要学多久网站建设与管理 市场分析
  • 潍坊网站建设排行房地产销售人员网站怎么做
  • 如何为你的项目选择合适的加速度计?
  • 【MySQL】索引 知识总结
  • 拍卖公司资质的办理流程
  • 北京医院网站建设wordpress二次开发视频教程
  • 如何在淘宝网做自己的网站制作网站规划书
  • Rust 练习册 16:Trait 作为返回类型
  • LeetCode热题100--46. 全排列--中等
  • 有域名了怎么做网站冷水滩网站建设
  • 1.7 微调方法比较(LoRA、P-Tuning v2、Adapter):构建高效定制化AI模型
  • DO后缀命名在DDD(领域驱动设计)的错误应用
  • 中国平湖首页规划建设局网站电子商务网站建设课程设计总结
  • 数据结构系列之快速排序
  • 解决PowerShell执行策略导致的npm脚本无法运行问题
  • FPGA教程系列-Vivado IP核之乘法器解析
  • 开源网站 做镜像 如何做邯山网站制作
  • 挖掘百亿“数字热土”!解读印度游戏与媒体娱乐的高速增长
  • 做一套网站多钱做网站 源代码
  • 怎么做网站免织梦网站分享插件
  • 单链表反转:从基础到进阶的完整指南
  • 医疗机器人的智能感知:六维力传感器如何提升手术安全与精度?
  • STM32外设学习--TIM定时器--输入捕获---测频方法。
  • 网站开发的国内外研究现状微信网站设计模板下载