【crossbeam系列】4 crossbeam-channel:增强版channel

这一期的内容会轻松一些,讲讲crossbeam中的channel。但是有人就要问了在标准库里面已经有了 std::sync::mpsc ,为何crossbeam又要搞出一套channel呢?首先咱们来看看标准库中的channel有哪些不足吧

标准库中channel的不足

  1. Receiver不能被clone,是MPSC的channel。理想情况咱们但愿能有MPMC的channel
  2. Sender和Receiver不是 Sync
  3. 在Go语言中,channel通常和 select 语句一块儿使用,可是标准库中的channel并不支持select
  4. 有限容量(Bounded)的channel内部实现就是一个简单的 Mutex<VecDeque<T>> ,性能比Go语言的channel还差
  5. 有Sender(=Unbouded)和SyncSender(=Bounded)的区分,用起来不统一。

crossbeam中增强版的channel

首先,不管容量是否有限,Sender类型统一成一种,这样用起来就很方便。其次对有限容量的channel进行了重写(还记得上一期咱们讲的Deque其实就是为了消除 Mutex<VecDeque<T>> 产生的瓶颈么,这里也相似。对于1-3点:(在此以前咱们先简单讲下如何建立crossbeam的channel)

建立channel

有限容量
   
use crossbeam_channel::bounded;

// 建立一个容量是5的channel
let (s, r) = bounded(5);

// 5条消息以内都不会阻塞
for i in 0..5 {
s.send(i).unwrap();
}

// 超过5条就会阻塞了
// s.send(5).unwrap();
无限容量
   
use crossbeam_channel::unbounded;

// 建立一个无限容量的channel
let (s, r) = unbounded();

// 不会阻塞
for i in 0..1000 {
s.send(i).unwrap();
}
·

1 支持MPMC

如今终于不用笨拙地给Receiver端加锁了~
   
use std::thread;
use crossbeam_channel::bounded;

let (s1, r1) = bounded(0);
let (s2, r2) = (s1.clone(), r1.clone());

// 起一个线程先接受一个消息而后发出一个消息
thread::spawn(move || {
r2.recv().unwrap();
s2.send(2).unwrap();
});

// 发送一个消息而后接受一个消息
s1.send(1).unwrap();
r1.recv().unwrap();

2 Sender和Receiver是Sync

因此如今能够把引用在线程间传递了
   
use std::thread;
use crossbeam_channel::bounded;
use crossbeam_utils::thread::scope;

let (s, r) = bounded(0);

scope(|scope| {
// 起一个线程先接受一个消息而后发出一个消息
scope.spawn(|_| {
r.recv().unwrap();
s.send(2).unwrap();
});

// 发送一个消息而后接受一个消息
s.send(1).unwrap();
r.recv().unwrap();
}).unwrap();

3 支持select

提供了相似Go语言功能的 select 宏,支持使用 default 分支处理超时等逻辑
   
use std::thread;
use std::time::Duration;
use crossbeam_channel::unbounded;

let (s1, r1) = unbounded();
let (s2, r2) = unbounded();

thread::spawn(move || s1.send(10).unwrap());
thread::spawn(move || s2.send(20).unwrap());

select! {
recv(r1) -> msg => assert_eq!(msg, Ok(10)),
recv(r2) -> msg => assert_eq!(msg, Ok(20)),
default(Duration::from_secs(1)) => println!("timed out"),
}
而且其实select内部不单单支持接受消息,也支持发送消息。同时还有更高级的动态select支持~

小结

咱们看到,crossbeam的channel优雅的解决了标准库中上述的5个问题,看来没事能够多用用了~下一期咱们会讲一下crossbeam-util和crossbeam-queue,敬请期待。

本文分享自微信公众号 - Rust语言中文社区(rust-china)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。微信

相关文章
相关标签/搜索