這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
本文翻譯自:https://idea.popcount.org/2017-02-23-socket-api-thoughts/
前一段時間,我寫了篇關於select()系統調用發展曆史的文章。 該文章引發了一些有趣的討論。
文章和討論花了我不少心思,但我最終明白了什麼是核心問題:
Unix進程是否是CSP風格的進程? 檔案描述符是CSP派生的“通道”嗎? “select()”相當於ALT語句嗎?
直接的答案是“不”。 CSP比Unix更年輕。 正如Tony Garnock-Jones指出的,關於CSP的第一篇文章發表於1978年,檔案描述符自從Unix的早期就已經出現。
檔案描述符不是通道,他們應該是什嗎? CSP channel通常是可組合的,而我認為Unix的select不是。 這是第二點:
使用“select()”的Unix程式不使用組合。 但也許他們可以用? “select()能否以允許組合性的方式實現”?
當在Golang中編程時,可以使用ALT語句和內建channel。 一般來說,golang channel是可組合的。 類似的事情在Erlang中 - 你可以通過巧妙地使用gen_server進程來避免複雜的狀態機器。
Unix進程模型為何不能如此? 為什麼我們不能以組合Golang或Erlang相同的方式來組合Unix進程?
我會直覺地指責select系統調用,但問題更深入。
緩衝代理
我們不能放棄select? 我們可以沒有它嗎? 在前面的文章中我們提到了兩個例子:
還有很多問題都離不開select。 David Wragg提到“緩衝代理”問題:
想象一個進行緩衝的進程。 考慮一個簡單的程式,從一個流讀取資料,緩衝它,並寫入另一個流。 如果使用它們之間的管道將它拆分為兩個進程,則會受到核心管道緩衝區大小的限制。 為了具有任意的緩衝區大小,它必須在單個進程中進行輸入資料流的可讀性和輸出資料流的可寫性的select操作。
克裡斯·西本曼在2010年的部落格中提到了同樣的問題。
空閑串連的記憶體消耗
今年早些時候,Chris提到了另一個需要select的問題:“空閑串連的記憶體消耗”:
這篇文章是Evan Klitzke的文章的後續:
這個記憶體消耗的論點在Golang Bug跟蹤器中提出:
net:在TCPConn上添加等待機制
對我來說,這聽起來像在介紹回調地獄。
BSD Socket API 改造
最後,Martin Sustrick針對純粹阻塞通訊端API寫了這個RFC提案:
BSD Socket API 改造
YCombinator討論
本文沒有通過推動select問題到下一層來解決問題:
該備忘錄假設已經存在有效並發實現,其建立新的輕量級進程需要最多幾百納秒並且環境切換需要幾十納秒。 注意,已經部署了這樣的並發系統。 一個著名的例子是Golang的goroutine,但也有其他可用的。
我非常喜歡只暴露阻塞API給使用者的想法。
最終想法
雖然Unix socket模型和CSP已經存在了將近40年,但它們不是各自封閉的。 在這方面有很多新想法:最佳化記憶體使用量,找到合適的可組合性抽象,回到暴露純粹阻塞API。