通道 (編程)
在計算中,通道(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線程模型。