文章目錄
- 第15章 併發編程
- 15.1 使用線程同時運行代碼
- 線程基礎與創建
- 基本線程操作
- 線程與所有權
- 線程管理與配置
- 錯誤處理與恐慌傳播
- 15.2 消息傳遞併發
- 通道基礎
- 基本通道操作
- 多生產者場景
- 同步通道
- 高級通道模式
- 15.3 共享狀態併發
- Mutex互斥鎖
- 基本Mutex使用
- 高級Mutex模式
- RwLock讀寫鎖
- 條件變量
- 原子類型
- 15.4 Sync和Send trait
- Send Trait
- Sync Trait
- 自定義Send和Sync類型
- 實戰:構建併發Web服務器
- 併發編程最佳實踐
- 性能優化建議
- 總結
第15章 併發編程
併發編程是現代軟件開發中不可或缺的重要組成部分,它允許程序同時執行多個任務,從而充分利用多核處理器的能力,提高程序的性能和響應性。Rust以其獨特的所有權系統和類型系統,在保證內存安全的同時,提供了強大而靈活的併發編程能力。本章將深入探討Rust的併發編程特性,包括線程管理、消息傳遞、共享狀態以及Sync和Send trait。
15.1 使用線程同時運行代碼
線程基礎與創建
線程是操作系統能夠進行運算調度的最小單位,Rust標準庫提供了強大的線程支持,允許我們創建和管理多個併發執行的線程。
基本線程操作
use std::thread;
use std::time::Duration;
fn thread_basics() {
println!("=== 線程基礎演示 ===");
// 創建新線程
let handle = thread::spawn(|| {
for i in 1..=5 {
println!("子線程: 計數 {}", i);
thread::sleep(Duration::from_millis(500));
}
});
// 主線程繼續執行
for i in 1..=3 {
println!("主線程: 計數 {}", i);
thread::sleep(Duration::from_millis(300));
}
// 等待子線程完成
handle.join().unwrap();
println!("所有線程執行完成");
}
線程與所有權
由於線程可能比創建它們的函數活得更久,因此線程閉包經常需要使用move關鍵字來獲取所需數據的所有權。
fn thread_ownership() {
println!("=== 線程與所有權 ===");
let data = vec![1, 2, 3, 4, 5];
// 使用move關鍵字將data的所有權轉移到線程中
let handle = thread::spawn(move || {
println!("在線程中訪問數據: {:?}", data);
// data在這裏被消費
});
// 這裏不能再使用data,因為所有權已經移動到了線程中
// println!("{:?}", data); // 這行會編譯錯誤
handle.join().unwrap();
// 共享不可變數據
let shared_data = Arc::new(vec!["hello", "world", "from", "threads"]);
let mut handles = vec![];
for i in 0..3 {
let data_clone = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
println!("線程 {}: 數據長度 = {}", i, data_clone.len());
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
線程管理與配置
Rust允許我們配置線程的各個方面,包括棧大小、名稱等。
fn thread_management() {
println!("=== 線程管理 ===");
// 創建帶配置的線程
let builder = thread::Builder::new()
.name("worker-thread".into())
.stack_size(32 * 1024); // 32KB棧大小
let handle = builder.spawn(|| {
let name = thread::current().name().unwrap_or("unnamed");
println!("線程 '{}' 開始執行", name);
// 模擬工作
for i in 1..=3 {
println!("線程 '{}' 工作 {}...", name, i);
thread::sleep(Duration::from_millis(200));
}
println!("線程 '{}' 執行完成", name);
}).unwrap();
handle.join().unwrap();
// 獲取系統信息
println!("可用的並行度: {:?}", thread::available_parallelism());
}
錯誤處理與恐慌傳播
線程中的恐慌不會自動傳播到主線程,但我們可以通過JoinHandle來檢測和處理。
fn thread_error_handling() {
println!("=== 線程錯誤處理 ===");
// 正常執行的線程
let success_handle = thread::spawn(|| {
println!("這個線程會正常完成");
42
});
// 會恐慌的線程
let panic_handle = thread::spawn(|| {
println!("這個線程將會恐慌");
panic!("故意製造的恐慌!");
});
// 處理正常線程的結果
match success_handle.join() {
Ok(result) => println!("正常線程結果: {}", result),
Err(_) => println!("正常線程意外恐慌"),
}
// 處理恐慌線程
match panic_handle.join() {
Ok(_) => println!("恐慌線程正常完成 - 這不應該發生"),
Err(e) => {
println!("捕獲到線程恐慌");
if let Some(s) = e.downcast_ref::<&str>() {
println!("恐慌信息: {}", s);
}
}
}
}
15.2 消息傳遞併發
通道基礎
通道是Rust中實現消息傳遞併發的主要機制,它允許多個線程之間通過發送和接收消息來進行通信。
基本通道操作
use std::sync::mpsc; // mpsc: 多個生產者,單個消費者
fn channel_basics() {
println!("=== 通道基礎 ===");
// 創建通道
let (tx, rx) = mpsc::channel();
// 在子線程中發送消息
thread::spawn(move || {
let messages = vec!["hello", "world", "from", "thread"];
for msg in messages {
tx.send(msg.to_string()).unwrap();
thread::sleep(Duration::from_millis(100));
}
// tx在這裏被丟棄,通道會自動關閉
});
// 在主線程中接收消息
for received in rx {
println!("收到: {}", received);
}
println!("通道已關閉,所有消息已接收");
}
多生產者場景
fn multiple_producers() {
println!("=== 多生產者示例 ===");
let (tx, rx) = mpsc::channel();
let mut handles = vec![];
// 創建多個生產者線程
for producer_id in 0..3 {
let thread_tx = tx.clone(); // 克隆發送端
let handle = thread::spawn(move || {
for i in 0..3 {
let message = format!("生產者 {} - 消息 {}", producer_id, i);
thread_tx.send(message).unwrap();
thread::sleep(Duration::from_millis(50));
}
println!("生產者 {} 完成", producer_id);
});
handles.push(handle);
}
// 丟棄原始的tx,這樣當所有克隆的tx都被丟棄時,通道會關閉
drop(tx);
// 接收所有消息
let mut received_count = 0;
for message in rx {
println!("消費者收到: {}", message);
received_count += 1;
}
println!("總共收到 {} 條消息", received_count);
// 等待所有生產者線程完成
for handle in handles {
handle.join().unwrap();
}
}
同步通道
Rust還提供了同步通道,它在發送時會阻塞直到消息被接收。
fn sync_channels() {
println!("=== 同步通道 ===");
// 創建同步通道,緩衝區大小為2
let (tx, rx) = mpsc::sync_channel(2);
let producer_handle = thread::spawn(move || {
for i in 0..5 {
println!("生產者準備發送消息 {}", i);
tx.send(i).unwrap();
println!("生產者成功發送消息 {}", i);
}
});
// 慢速消費,演示同步行為
for _ in 0..5 {
thread::sleep(Duration::from_millis(500));
let msg = rx.recv().unwrap();
println!("消費者收到: {}", msg);
}
producer_handle.join().unwrap();
}
高級通道模式
fn advanced_channel_patterns() {
println!("=== 高級通道模式 ===");
// 1. 帶超時的接收
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
thread::sleep(Duration::from_millis(500));
tx.send("延遲的消息".to_string()).unwrap();
});
match rx.recv_timeout(Duration::from_millis(100)) {
Ok(msg) => println!("及時收到: {}", msg),
Err(mpsc::RecvTimeoutError::Timeout) => println!("接收超時"),
Err(mpsc::RecvTimeoutError::Disconnected) => println!("通道已斷開"),
}
// 2. 非阻塞接收
let (tx, rx) = mpsc::channel();
match rx.try_recv() {
Ok(msg) => println!("立即收到: {}", msg),
Err(mpsc::TryRecvError::Empty) => println!("沒有可用消息"),
Err(mpsc::TryRecvError::Disconnected) => println!("通道已斷開"),
}
tx.send("測試消息".to_string()).unwrap();
// 3. 選擇操作(使用crossbeam-channel,功能更強大)
#[cfg(feature = "crossbeam")]
{
use crossbeam_channel::{select, unbounded};
let (tx1, rx1) = unbounded();
let (tx2, rx2) = unbounded();
thread::spawn(move || {
thread::sleep(Duration::from_millis(100));
tx1.send("第一個通道").unwrap();
});
thread::spawn(move || {
thread::sleep(Duration::from_millis(200));
tx2.send("第二個通道").unwrap();
});
select! {
recv(rx1) -> msg => println!("從 {} 收到消息", msg.unwrap()),
recv(rx2) -> msg => println!("從 {} 收到消息", msg.unwrap()),
}
}
}
15.3 共享狀態併發
Mutex互斥鎖
Mutex(互斥鎖)是共享狀態併發的基礎,它保證一次只有一個線程可以訪問數據。
基本Mutex使用
use std::sync::{Mutex, Arc};
fn mutex_basics() {
println!("=== Mutex基礎 ===");
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!("最終計數: {}", *counter.lock().unwrap());
}
高級Mutex模式
fn advanced_mutex_patterns() {
println!("=== 高級Mutex模式 ===");
// 1. 帶複雜數據的Mutex
struct SharedData {
values: Vec<i32>,
metadata: String,
}
let shared_data = Arc::new(Mutex::new(SharedData {
values: Vec::new(),
metadata: "初始狀態".to_string(),
}));
let mut handles = vec![];
for i in 0..5 {
let data = Arc::clone(&shared_data);
let handle = thread::spawn(move || {
let mut guard = data.lock().unwrap();
guard.values.push(i);
guard.metadata = format!("由線程 {} 更新", i);
println!("線程 {} 更新了數據", i);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let final_data = shared_data.lock().unwrap();
println!("最終數據: {:?}", final_data.values);
println!("元數據: {}", final_data.metadata);
// 2. 嘗試鎖
let data = Arc::new(Mutex::new(0));
let data_clone = Arc::clone(&data);
// 在一個線程中持有鎖
let holder_handle = thread::spawn(move || {
let _guard = data_clone.lock().unwrap();
println!("持有鎖的線程開始睡眠");
thread::sleep(Duration::from_secs(2));
println!("持有鎖的線程釋放鎖");
});
thread::sleep(Duration::from_millis(100));
// 嘗試獲取鎖
match data.try_lock() {
Ok(mut guard) => {
println!("成功獲取鎖");
*guard += 1;
}
Err(_) => {
println("無法獲取鎖,鎖正被其他線程持有");
}
}
holder_handle.join().unwrap();
}
RwLock讀寫鎖
RwLock(讀寫鎖)允許多個讀取者或一個寫入者同時訪問數據,適用於讀多寫少的場景。
use std::sync::RwLock;
fn rwlock_example() {
println!("=== RwLock示例 ===");
let data = Arc::new(RwLock::new(String::from("初始值")));
let mut handles = vec![];
// 創建多個讀取者
for reader_id in 0..3 {
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
for _ in 0..3 {
let value = data.read().unwrap();
println!("讀取者 {}: {}", reader_id, *value);
thread::sleep(Duration::from_millis(100));
}
});
handles.push(handle);
}
// 創建一個寫入者
let writer_data = Arc::clone(&data);
let writer_handle = thread::spawn(move || {
for i in 0..2 {
thread::sleep(Duration::from_millis(200));
let mut value = writer_data.write().unwrap();
*value = format!("被寫入者修改的值 {}", i);
println!("寫入者: 更新值為 {}", *value);
}
});
handles.push(writer_handle);
for handle in handles {
handle.join().unwrap();
}
println!("最終值: {}", *data.read().unwrap());
}
條件變量
條件變量允許線程在等待某個條件成立時掛起,並在條件可能成立時被喚醒。
use std::sync::{Condvar, Mutex};
fn condition_variable_example() {
println!("=== 條件變量示例 ===");
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = Arc::clone(&pair);
// 等待條件的線程
let waiter_handle = thread::spawn(move || {
let (lock, cvar) = &*pair2;
let mut started = lock.lock().unwrap();
println!("等待線程: 等待條件成立");
while !*started {
started = cvar.wait(started).unwrap();
}
println!("等待線程: 條件成立,繼續執行");
});
// 設置條件的線程
thread::spawn(move || {
let (lock, cvar) = &*pair;
println!("設置線程: 工作2秒...");
thread::sleep(Duration::from_secs(2));
println!("設置線程: 設置條件並通知");
{
let mut started = lock.lock().unwrap();
*started = true;
}
cvar.notify_one();
});
waiter_handle.join().unwrap();
println!("所有線程完成");
}
原子類型
原子類型提供了無需互斥鎖的線程安全操作,性能更高但功能有限。
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn atomic_operations() {
println!("=== 原子操作 ===");
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 || {
for _ in 0..1000 {
counter.fetch_add(1, Ordering::SeqCst);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最終計數: {}", counter.load(Ordering::SeqCst));
// 比較並交換操作
let value = Arc::new(AtomicUsize::new(0));
let mut swap_handles = vec![];
for i in 0..5 {
let value = Arc::clone(&value);
let handle = thread::spawn(move || {
let mut current = value.load(Ordering::SeqCst);
loop {
let new = current + 1;
match value.compare_exchange_weak(
current,
new,
Ordering::SeqCst,
Ordering::SeqCst
) {
Ok(_) => {
println!("線程 {} 成功將值從 {} 更新到 {}", i, current, new);
break;
}
Err(actual) => {
println!("線程 {} 更新失敗,當前值為 {}", i, actual);
current = actual;
}
}
}
});
swap_handles.push(handle);
}
for handle in swap_handles {
handle.join().unwrap();
}
println!("最終值: {}", value.load(Ordering::SeqCst));
}
15.4 Sync和Send trait
Send Trait
Send marker trait表示類型的所有權可以在線程間安全傳遞。
fn send_trait_demo() {
println!("=== Send Trait 演示 ===");
// 大多數類型都是Send的
let value = 42;
let handle = thread::spawn(move || {
println!("在線程中使用值: {}", value);
});
handle.join().unwrap();
// 一些類型不是Send的,比如Rc<T>
let rc_value = std::rc::Rc::new(42);
// 下面的代碼會編譯錯誤,因為Rc<T>不是Send的
// let handle = thread::spawn(move || {
// println!("Rc value: {}", rc_value);
// });
println!("Rc<T> 不是 Send,因此不能跨線程傳遞");
// 但Arc<T>是Send的
let arc_value = std::sync::Arc::new(42);
let handle = thread::spawn(move || {
println!("Arc value: {}", arc_value);
});
handle.join().unwrap();
println!("Arc<T> 是 Send,可以跨線程傳遞");
}
Sync Trait
Sync marker trait表示類型的引用可以安全地在多個線程間共享。
fn sync_trait_demo() {
println!("=== Sync Trait 演示 ===");
// 不可變引用是Sync的
let data = vec![1, 2, 3];
let data_ref = &data;
let handle = thread::spawn(move || {
println!("在線程中訪問數據長度: {}", data_ref.len());
});
handle.join().unwrap();
// Mutex<T>是Sync的,即使T不是
let mutex_data = Arc::new(Mutex::new(vec![1, 2, 3]));
let mut handles = vec![];
for i in 0..3 {
let data = Arc::clone(&mutex_data);
let handle = thread::spawn(move || {
let mut guard = data.lock().unwrap();
guard.push(i);
println!("線程 {} 添加了值 {}", i, i);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最終數據: {:?}", mutex_data.lock().unwrap());
// Cell<T>不是Sync的
let cell_data = std::cell::Cell::new(42);
// 下面的代碼會編譯錯誤,因為Cell<T>不是Sync的
// let handle = thread::spawn(move || {
// cell_data.set(100);
// });
println!("Cell<T> 不是 Sync,不能跨線程共享引用");
}
自定義Send和Sync類型
我們可以為自己的類型手動實現Send和Sync trait,但需要確保線程安全性。
// 自定義線程安全類型
struct ThreadSafeCounter {
count: AtomicUsize,
name: String,
}
impl ThreadSafeCounter {
fn new(name: &str) -> Self {
ThreadSafeCounter {
count: AtomicUsize::new(0),
name: name.to_string(),
}
}
fn increment(&self) -> usize {
self.count.fetch_add(1, Ordering::SeqCst)
}
fn get(&self) -> usize {
self.count.load(Ordering::SeqCst)
}
}
// 因為只包含Send和Sync的字段,所以自動實現Send和Sync
// 我們可以顯式聲明,但編譯器會自動推導
// unsafe impl Send for ThreadSafeCounter {}
// unsafe impl Sync for ThreadSafeCounter {}
fn custom_send_sync_demo() {
println!("=== 自定義 Send + Sync 類型 ===");
let counter = Arc::new(ThreadSafeCounter::new("global_counter"));
let mut handles = vec![];
for i in 0..5 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
for _ in 0..100 {
let old = counter.increment();
println!("線程 {}: 計數從 {} 增加到 {}", i, old, old + 1);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("最終計數: {}", counter.get());
}
實戰:構建併發Web服務器
讓我們構建一個簡單的併發Web服務器來展示這些概念的組合使用。
use std::io::{Read, Write};
use std::net::{TcpListener, TcpStream};
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
struct ThreadPool {
workers: Vec<Worker>,
sender: mpsc::Sender<Message>,
}
type Job = Box<dyn FnOnce() + Send + 'static>;
enum Message {
NewJob(Job),
Terminate,
}
impl ThreadPool {
fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender }
}
fn execute<F>(&self, f: F)
where
F: FnOnce() + Send + 'static,
{
let job = Box::new(f);
self.sender.send(Message::NewJob(job)).unwrap();
}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
println!("正在停止所有工作線程...");
for _ in &self.workers {
self.sender.send(Message::Terminate).unwrap();
}
for worker in &mut self.workers {
println!("關閉工作線程 {}", worker.id);
if let Some(thread) = worker.thread.take() {
thread.join().unwrap();
}
}
}
}
struct Worker {
id: usize,
thread: Option<thread::JoinHandle<()>>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
let thread = thread::spawn(move || loop {
let message = receiver.lock().unwrap().recv().unwrap();
match message {
Message::NewJob(job) => {
println!("工作線程 {} 獲得任務,執行中。", id);
job();
}
Message::Terminate => {
println!("工作線程 {} 收到終止信號。", id);
break;
}
}
});
Worker {
id,
thread: Some(thread),
}
}
}
fn handle_connection(mut stream: TcpStream, request_count: Arc<AtomicUsize>) {
let mut buffer = [0; 1024];
stream.read(&mut buffer).unwrap();
let request_count = request_count.fetch_add(1, Ordering::SeqCst) + 1;
let get = b"GET / HTTP/1.1\r\n";
let sleep = b"GET /sleep HTTP/1.1\r\n";
let (status_line, contents) = if buffer.starts_with(get) {
("HTTP/1.1 200 OK", "<h1>Hello!</h1><p>這是快速響應</p>")
} else if buffer.starts_with(sleep) {
thread::sleep(Duration::from_secs(5));
("HTTP/1.1 200 OK", "<h1>Hello!</h1><p>這是慢速響應</p>")
} else {
("HTTP/1.1 404 NOT FOUND", "<h1>Oops!</h1><p>頁面未找到</p>")
};
let response = format!(
"{}\r\nContent-Length: {}\r\n\r\n{}",
status_line,
contents.len(),
contents
);
stream.write(response.as_bytes()).unwrap();
stream.flush().unwrap();
println!("請求 #{} 已處理", request_count);
}
fn concurrent_web_server() {
println!("=== 併發Web服務器演示 ===");
let listener = TcpListener::bind("127.0.0.1:8080").unwrap();
let pool = ThreadPool::new(4);
let request_count = Arc::new(AtomicUsize::new(0));
println!("服務器運行在 http://127.0.0.1:8080");
println!("可用端點:");
println!(" GET / - 快速響應");
println!(" GET /sleep - 5秒延遲響應");
println!(" 其他路徑 - 404響應");
for stream in listener.incoming().take(10) { // 只處理10個連接用於演示
let stream = stream.unwrap();
let request_count = Arc::clone(&request_count);
pool.execute(move || {
handle_connection(stream, request_count);
});
}
println!("已處理10個請求,服務器關閉");
}
fn main() {
thread_basics();
thread_ownership();
thread_management();
thread_error_handling();
channel_basics();
multiple_producers();
sync_channels();
advanced_channel_patterns();
mutex_basics();
advanced_mutex_patterns();
rwlock_example();
condition_variable_example();
atomic_operations();
send_trait_demo();
sync_trait_demo();
custom_send_sync_demo();
concurrent_web_server();
}
併發編程最佳實踐
性能優化建議
fn concurrency_best_practices() {
println!("=== 併發編程最佳實踐 ===");
println!("\n1. 選擇合適的併發模型:");
println!(" - 消息傳遞: 適用於任務間通信");
println!(" - 共享狀態: 適用於需要共享數據的場景");
println!(" - 無鎖數據結構: 適用於高性能場景");
println!("\n2. 避免鎖的濫用:");
println!(" - 儘量使用更細粒度的鎖");
println!(" - 考慮使用RwLock替代Mutex");
println!(" - 在可能的情況下使用原子操作");
println!("\n3. 處理錯誤和恐慌:");
println!(" - 總是處理線程的JoinHandle");
println!(" - 考慮使用catch_unwind處理恐慌");
println!(" - 確保資源在恐慌時也能正確清理");
println!("\n4. 性能考慮:");
println!(" - 避免不必要的線程創建");
println!(" - 使用線程池管理線程生命週期");
println!(" - 注意緩存一致性和false sharing");
println!("\n5. 測試和調試:");
println!(" - 使用工具檢測數據競爭");
println!(" - 編寫併發測試用例");
println!(" - 使用日誌和指標監控併發行為");
}
// 數據競爭檢測示例
#[cfg(test)]
mod concurrency_tests {
use super::*;
use std::sync::atomic::{AtomicBool, Ordering};
#[test]
fn test_thread_safety() {
let data = Arc::new(AtomicBool::new(false));
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
data_clone.store(true, Ordering::SeqCst);
});
handle.join().unwrap();
assert!(data.load(Ordering::SeqCst));
}
#[test]
fn test_message_passing() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(42).unwrap();
});
assert_eq!(rx.recv().unwrap(), 42);
}
}
總結
併發編程是Rust的強項之一,其所有權系統和類型系統在編譯時就能防止數據競爭和其他常見的併發錯誤。通過本章的學習,我們掌握了:
- 線程管理:創建、配置和管理線程,理解線程與所有權的關係
- 消息傳遞:使用通道進行線程間通信,包括多生產者和同步通道
- 共享狀態:使用Mutex、RwLock、條件變量和原子類型安全地共享數據
- Sync和Send trait:理解這些trait如何保證線程安全,以及如何創建自定義的線程安全類型
Rust的併發編程模型既強大又安全,能夠在編譯期捕獲許多其他語言在運行時才會發現的併發錯誤。通過合理運用這些工具和模式,我們可以構建出既高效又可靠的併發應用程序。
在下一章中,我們將探討Rust的面向對象編程特性,學習如何用Rust實現面向對象的設計模式,以及如何在Rust的哲學和麪向對象編程之間找到平衡。