通道 (编程)
在计算中,通道(channel)是通过消息传递进行进程间通信和同步的编程模型。作为一个流,消息可以经由通道发送,另一个进程或线程能够接收它已经引用的经由通道发送的消息。通道的不同实现,可以没有缓冲区也可以有缓冲区,消息传递相应的可以是同步的也可以是异步的。
通道是并发的进程演算方式的基础,并起源于通信顺序进程(CSP),它是并发的形式模型,在CSP的无缓冲区通道中,发送者不能传送消息,直到接收者准备好接受它,称为同步消息传递,这种行为也被形象的称为“约会”(rendezvous)。通道已经用在了很多CSP派生语言中,比如occam和Limbo编程语言(经历了Newsqueak和Alef语言)。通道还用于贝尔实验室Plan 9的libthread,以及用于Stackless Python和Go编程语言。
通道实现
[编辑]通道是固有同步I/O:一个进程等待接收来自一个通道的对象,它将会阻塞直到这个对象被发送了。
libthread通道
[编辑]多线程库libthread[1],它最初是为操作系统Plan 9建立的,提供了基于固定大小的通道的线程间通信。下面用libthread通道API的例子来说明典型支持的操作。
- 固定或可变大小的通道建立,返回引用或句柄(handle):
Channel* chancreate(int elemsize, int bufsize)
- 发送到一个通道:
int chansend(Channel *c, void *v)
- 接收自一个通道:
int chanrecv(Channel *c, void *v)
OCaml事件
[编辑]OCaml事件模块提供有类型的通道用于同步。在调用这个模块的发送和接收函数的时候,它们建立可以被同步的相应发送和接收事件。
例子
[编辑]Go
[编辑]Go允许通道缓冲内容,而且还有通过使用select
阻塞而得到的非阻塞接收[2]。下面是演示通道和goroutine协程用法Go代码片段:
c := make(chan int) // 分配一个通道
// 启动一个goroutine在其中做排序;当它完成时,在通道上发信号
go func() {
list.Sort()
c <- 1 // 发送一个信号,值无关紧要
}()
doSomethingForAWhile()
<-c // 等待排序结束;丢弃发来的值
Rust
[编辑]Rust提供了在线程之间的异步通道。通道允许在两个端点Sender
和Receiver
之间的单向的信息流动[3]:
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
tx.send(123).unwrap();
});
let result = rx.recv();
println!("{:?}", result);
}
应用
[编辑]除了用于进程间通信的基本用途之外,通道可以被用作实现能现实化为流的各种其他并发编程构造的原语(primitive)。例如,可以使用通道了构造Future与promise,这里的future是一个一元素通道,而promise是发送至这个通道的一个进程,它履行future[4]。类似的,迭代器可以直接用通道构造[5]。
引用
[编辑]- ^ thread(3) - Plan 9 from User Space. [2024-01-03]. (原始内容存档于2023-09-08).
- ^ 存档副本. [2020-05-04]. (原始内容存档于2015-01-06).
- ^ Channels - Rust By Example. doc.rust-lang.org. [28 November 2020]. (原始内容存档于2024-03-24).
- ^ "Futures (页面存档备份,存于互联网档案馆)", Go Language Patterns (页面存档备份,存于互联网档案馆)
- ^ "Iterators (页面存档备份,存于互联网档案馆)", Go Language Patterns (页面存档备份,存于互联网档案馆)
参见
[编辑]外部链接
[编辑]- Bell Labs and CSP Threads (页面存档备份,存于互联网档案馆),贝尔实验室及CSP线程模型。
- An Introduction to Programming with Threads (页面存档备份,存于互联网档案馆), 与“贝尔实验室及CSP线程”相对比的SRC线程模型。