Day 6:async 與並發資料共享(tokio 版)
學習目標
- 在 async 環境用共享狀態
- 用 tokio::sync 的型別取代 std::sync
- 處理不需要 clone 的共享資料
今日重點
std::sync::Mutex 在 async 的陷阱
在
.await之間**持有**std::sync::MutexGuard可能造成問題(不能跨 await 持有。會阻擋其他任務)。async 裡建議用tokio::sync::Mutex。
tokio::sync::Mutex
use tokio::sync::Mutex;
use std::sync::Arc;
struct Counter { value: Mutex<i32> }
#[tokio::main]
async fn main() {
let counter = Arc::new(Counter { value: Mutex::new(0) });
let mut handles = vec![];
for _ in 0..5 {
let c = Arc::clone(&counter);
handles.push(tokio::spawn(async move {
let mut v = c.value.lock().await;
*v += 1;
}));
}
for h in handles { h.await.unwrap(); }
println!("count = {}", counter.value.lock().await);
}
lock()也是 async(.await),因為在 async 環境中等待鎖也要讓出執行權。
broadcast(多訂閱者通道)
use tokio::sync::broadcast;
// tx.subscribe() 可建立多個接收者,適合 pub/sub
練習
use tokio::sync::Mutex;
use std::sync::Arc;
#[tokio::main]
async fn main() {
let shared = Arc::new(Mutex::new(0i64));
let mut handles = vec![];
for _ in 0..4 {
let shared = Arc::clone(&shared);
handles.push(tokio::spawn(async move {
for _ in 0..1000 { *shared.lock().await += 1; }
}));
}
for h in handles { h.await.unwrap(); }
println!("{}", *shared.lock().await); // 4000
}
自我檢查
- 知道 async 中 Mutex 的注意事項
- 會用 tokio::sync::Mutex
- 理解為什麼 lock() 在 tokio 是 async
- 知道 broadcast 通道的存在
深入連結
- tokio 官方文件(Synchronization, Broadcast)