crossbeam 是一个并发包, 还是挺好用的。
crossbeam = "0.8.1"
- AtomicCell: 线程安全的可变容器。
- crossbeam-channel: 多生产者多消费者通道。
- crossbeam-deque: 工作窃取双端队列。
- crossbeam-queue: 无锁队列(SegQueue 和 ArrayQueue)。
- crossbeam-skiplist: 并发跳表。
- crossbeam-epoch: 基于世代的内存回收机制。
有界通道(Bounded Channel):
use crossbeam::channel::bounded;
fn main() {
let (sender, receiver) = bounded(2);
sender.send("111").unwrap();
sender.send("222").unwrap();
// if sender.try_send("Hello").is_err() {
// println!("Buffer is full, unable to send");
// }
std::thread::spawn(move || {
sender.send("333");
});
// std::thread::sleep(std::time::Duration::from_secs(1));
let msg1=receiver.recv().unwrap();
let msg2=receiver.recv().unwrap();
println!("Received: {}", msg1); // Received: Hello 1
println!("Received: {}", msg2); // Received: Hello 2
// 这时,第三条消息还在发送,因为缓冲区是满的
let msg3 = receiver.recv().unwrap();
println!("Received: {}", msg3); // Received: Hello 3
// 超时尝试接收消息
//if let Ok(msg) = receiver.recv_timeout(Duration::from_secs(1)) {
// println!("Received: {}", msg);
//} else {
// println!("No message arrived within 1 second");
//}
}
无界通道
fn main() {
let (sender, receiver) = unbounded();
// 发送消息
sender.send("Hello from the thread").unwrap();
// 接收消息
let msg = receiver.recv().unwrap();
println!("{}", msg); // Hello from the thread
}
AtomicCell 只能存储实现了 Copy trait 的数据类型,因此我们不能直接使用 AtomicCell 来存储和管理 Worker 或其他复杂类型的数据。这一点在多线程编程中尤为重要,因为使用像 Worker 这样复杂的数据结构时,必须使用智能指针和同步原语(如 Arc 和 Mutex)来确保数据的安全访问。
use crossbeam::atomic::AtomicCell;
fn main() {
let atomic_value = AtomicCell::new(42);
// 在多个线程中安全地读写值
atomic_value.store(43);
println!("Value: {}", atomic_value.load()); // Value: 43
}
crossbeam-deque 是一个工作窃取(work-stealing)双端队列库,适用于任务调度和并行任务执行。它提供了一种灵活的机制来创建工作者线程,它们可以从自己的任务队列中获取任务,也可以从其他工作者的任务队列中窃取任务,以确保负载均衡。
crossbeam-deque 中主要包括以下几个结构:
Injector:全局任务注入器,用于将任务推入队列,以便工作者线程可以窃取任务执行。
Worker:创建两个工作者队列,每个工作者都能从自己的队列中获取任务。
Stealer:为每个工作者创建一个窃取者,允许一个工作者从另一个工作者的队列中窃取任务。
use crossbeam_deque::{Injector, Steal, Worker};
use std::sync::{Arc, Mutex};
use std::thread;
use crossbeam::atomic::AtomicCell;
fn main() {
// 创建一个全局任务注入器
let injector = Arc::new(Injector::new());
// 使用 Arc 和 Mutex 创建两个工作者
let worker1 = Arc::new(Mutex::new(Worker::<i32>::new_fifo()));
let worker2 = Arc::new(Mutex::new(Worker::<i32>::new_fifo()));
let stealer1 = worker1.lock().unwrap().stealer();
let stealer2 = worker2.lock().unwrap().stealer();
// 向注入器中推入一些任务
for i in 0..5 {
injector.push(i);
}
// 工作者线程
let worker1_clone = Arc::clone(&worker1);
let handle1 = thread::spawn(move || {
loop {
let mut worker1 = worker1_clone.lock().unwrap();
if let Some(task) = worker1.pop() {
println!("Worker 1 executing task: {}", task);
} else {
break;
}
}
});
// 另一个工作者线程
let worker2_clone = Arc::clone(&worker2);
let handle2 = thread::spawn(move || {
loop {
let mut worker2 = worker2_clone.lock().unwrap();
if let Some(task) = worker2.pop() {
println!("Worker 2 executing task: {}", task);
} else {
match stealer1.steal() {
Steal::Success(task) => println!("Worker 2 stole task from Worker 1: {}", task),
Steal::Empty => break,
Steal::Retry => continue,
}
}
}
});
// 窃取者线程
let injector_clone = Arc::clone(&injector);
let worker1_clone2 = Arc::clone(&worker1);
let handle3 = thread::spawn(move || {
loop {
match injector_clone.steal_batch_and_pop(&worker1_clone2.lock().unwrap()) {
Steal::Success(task) => println!("Worker 1 executing stolen task from injector: {}", task),
Steal::Empty => break,
Steal::Retry => continue,
}
}
});
handle1.join().unwrap();
handle2.join().unwrap();
handle3.join().unwrap();
}
SegQueue 是一个无锁 (lock-free) 的多生产者多消费者队列。它是非阻塞 (non-blocking) 的,这意味着它在操作时不会使用传统的锁 (Mutex 或类似机制) 来控制并发访问。这种设计使得 SegQueue 能够在高度并发的环境中表现出色。
use crossbeam_queue::SegQueue;
use std::sync::Arc;
use std::thread;
fn main() {
let queue = Arc::new(SegQueue::new());
// 创建生产者线程,向队列中推入数据
let producers: Vec<_> = (0..4).map(|i| {
let queue = Arc::clone(&queue);
thread::spawn(move || {
for j in 0..10 {
queue.push(i * 10 + j);
println!("Producer {} pushed {}", i, i * 10 + j);
}
})
}).collect();
// 等待所有生产者完成
for producer in producers {
producer.join().unwrap();
}
// 创建消费者线程,从队列中弹出数据
let consumers: Vec<_> = (0..4).map(|i| {
let queue = Arc::clone(&queue);
thread::spawn(move || {
loop {
match queue.pop() {
Some(value) => {
println!("Consumer {} popped {}", i, value);
},
None => {
// 如果队列为空,跳出循环
break;
}
}
}
})
}).collect();
// 等待所有消费者完成
for consumer in consumers {
consumer.join().unwrap();
}
}
crossbeam-skiplist 是一个用于并发环境的高效数据结构,支持快速的插入、删除和查找操作。跳表是一种有序的链表结构,它通过多级索引实现高效的搜索、插入和删除操作。crossbeam-skiplist 提供了一个线程安全的跳表实现,可以在高并发环境中使用。
use crossbeam_skiplist::SkipMap;
use std::sync::Arc;
use std::thread;
fn main() {
// 创建一个 SkipMap 实例
let map = Arc::new(SkipMap::new());
// 创建多个写入线程
let writers: Vec<_> = (0..4).map(|i| {
let map = Arc::clone(&map);
thread::spawn(move || {
for j in 0..10 {
map.insert(i * 10 + j, format!("value {}", i * 10 + j));
println!("Writer thread {} inserted key {}", i, i * 10 + j);
}
})
}).collect();
// 等待所有写入线程完成
for writer in writers {
writer.join().unwrap();
}
// 创建多个读取线程
let readers: Vec<_> = (0..4).map(|i| {
let map = Arc::clone(&map);
thread::spawn(move || {
for j in 0..10 {
let key = i * 10 + j;
if let Some(entry) = map.get(&key) {
println!("Reader thread {} found key {}: {}", i, key, entry.value());
} else {
println!("Reader thread {} did not find key {}", i, key);
}
}
})
}).collect();
// 等待所有读取线程完成
for reader in readers {
reader.join().unwrap();
}
// 删除部分数据
for key in 0..10 {
map.remove(&key);
println!("Removed key {}", key);
}
// 检查是否成功删除
for key in 0..10 {
if let Some(entry) = map.get(&key) {
println!("Key {} still exists: {}", key, entry.value());
} else {
println!("Key {} has been removed", key);
}
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。