可能导致性能问题的原因
- 锁争用:大量线程同时尝试获取
Mutex
锁,导致锁争用严重。每次只有一个线程能获取锁并访问共享资源,其他线程处于等待状态,这大大增加了线程上下文切换开销,降低了整体性能。
- 粒度问题:如果
Mutex
保护的资源粒度太粗,即使不同线程只需要访问资源的不同部分,也都需要获取整个锁,进一步加剧了锁争用。
性能优化策略
- 减小锁粒度:将大的共享资源拆分成多个小的部分,每个部分由独立的
Mutex
保护。这样不同线程可以并发访问不同部分的资源,减少锁争用。
- 读写锁优化:如果对共享资源的访问读操作远多于写操作,可以使用
RwLock
代替 Mutex
。读操作可以并发执行,只有写操作需要独占锁,提高了并发读的效率。
代码示例
- 减小锁粒度
use std::sync::{Arc, Mutex};
// 定义多个小的共享资源
struct SmallResource {
data: i32,
}
struct BigResource {
part1: Arc<Mutex<SmallResource>>,
part2: Arc<Mutex<SmallResource>>,
}
impl BigResource {
fn new() -> BigResource {
BigResource {
part1: Arc::new(Mutex::new(SmallResource { data: 0 })),
part2: Arc::new(Mutex::new(SmallResource { data: 0 })),
}
}
}
fn main() {
let resource = Arc::new(BigResource::new());
// 模拟两个线程分别访问不同部分的资源
let handle1 = std::thread::spawn({
let resource = resource.clone();
move || {
let mut part1 = resource.part1.lock().unwrap();
part1.data += 1;
}
});
let handle2 = std::thread::spawn({
let resource = resource.clone();
move || {
let mut part2 = resource.part2.lock().unwrap();
part2.data += 1;
}
});
handle1.join().unwrap();
handle2.join().unwrap();
}
- 读写锁优化
use std::sync::{Arc, RwLock};
struct SharedData {
value: i32,
}
fn main() {
let data = Arc::new(RwLock::new(SharedData { value: 0 }));
// 模拟多个读线程
let mut read_handles = Vec::new();
for _ in 0..10 {
let data = data.clone();
let handle = std::thread::spawn(move || {
let shared_data = data.read().unwrap();
println!("Read value: {}", shared_data.value);
});
read_handles.push(handle);
}
// 模拟一个写线程
let write_handle = std::thread::spawn({
let data = data.clone();
move || {
let mut shared_data = data.write().unwrap();
shared_data.value += 1;
}
});
for handle in read_handles {
handle.join().unwrap();
}
write_handle.join().unwrap();
}