程序間以結構化數據而不是字元串傳遞信息是否更合理?

王垠:Unix的缺陷-(經驗之談)-PYTHON開發者社區-pythoner.org


挺有趣的想法

前一陣在玩Python的時候就有這種感覺了。

Python可以通過ctypes包直接調用c語言的dll,當時腦洞大開,如果直接用python做shell,各個函數都編譯成dll,各個函數之間的數據就可以通用了。如果這麼做,其實就可以算是很簡陋地實現了wangyin說的那種功能,只不過這裡python環境,就是他說的虛擬機,數據的標準化由python完成。

這裡還有些漏洞,就是ctypes現在只能完美支持C,C++的還需要編譯介面文件。

另外其實最好的是系統維護一份通用的各個函數/軟體/app的源代碼,結合當前硬體環境,編譯二進位文件,然後調用時統一調用,結構化數據直接在python(python-shell?)傳遞。

當然,不一定非得是python,其實ruby啊什麼好些其他的動態語言,也有同樣的能力。

這樣的實現主要是可以最小化程序為函數,把鏈接的功能交給傳統意義上的shell了。

其實前一陣看dRuby(分散式Ruby)的時候,還有一點感覺,腦洞可以再大一點,把各個程序、函數註冊成服務,就可以把數據跨網路傳遞。跟前一陣社會熱點的透明計算,概念上有點像。一個程序中,各個功能不一定都在本地,或者都編譯成一個完整的函數,可以由分布在各個不同物理位置的函數共同實現,中間數據的傳遞靠一種動態語言維護(例如舉例用到的Python、Ruby)。如果再同時把這種動態語言作為shell使用,操作系統確實就是一個虛擬機,甚至也可以被虛擬化。運算操作就完全脫離物理條件限制了。

怎麼感覺這個事現在已經完全可以做了呢。

可以設置這樣一種雲平台,把函數放在伺服器上,作者、維護人員在平台上修改代碼,伺服器自動編譯(也就是為了提高性能,如果性能不是那麼緊要,可以直接執行動態語言),同時向外部展示介面。用戶直接用動態語言鏈接過來,輸入輸出數據。感覺上有點像github加上AWS。當然,為了提高性能,以及適應離線環境,還是需要下載到本地。離線也才用同樣的調用機制,也還是可以的,就是不知道性能損失有多少了,是否性能上可以保證。

-------------------------------------更新---------------------------------------------------------

最近幾周學了 julia。有 ccall,PyCall.jl,RCall.jl,MATLAB.jl等等,感覺比 Python 更適合做膠水。


準確的說是基於文本的結構化數據更合理,比如json。為什麼webservice這麼流行,很大成都上就是因為它是基於文本的。而基於對象的,比如corba,rmi,很少有人用了。


回答題主之前,我想先扯扯我對王垠這篇文章的讀後感。

仔細看了一下這篇文章,限於我自己目前的學識水平,有些點沒有特別GET到。不過我覺得文章的主要篇幅說的其實主要是人類用戶與機器系統之間的交互或通信問題,而不是進程與進程間的通信問題。

準確的說,是人機通信之間的歧義問題。

在這個問題上,文章中所描述的那種理想方案,是讓人類用戶直接以某種腳本語言的函數調用的方式去跟機器系統交互。而且這種語言必須得是語法靠譜的、跨平台的、統一通用的。

換種理解方式,這種解決方案就是約定一個統一的、嚴密的編碼協議格式來表示指令和數據。對於編程語言來說這個協議就是它自己的語法。

現有的命令行交互方式存在的問題就是人機通信協議太簡單隨意、不夠嚴密,存在的協議歧義漏洞會使得有時候會無法正確區分指令和數據,或者無法區分各個數據單元。

文中舉的那個ls命令例子,簡化一點就是,如果當前目錄下有個文件名叫做-l,那麼命令ls -l是想要單獨查看名叫-l的這個文件嗎?所以這是有歧義的。

採用嚴格的協議可能會使得通信更加精準,也就是機器友好,但是反過來對普通用戶卻是非常不友好的。現有的命令行可以看做是在機器友好度和用戶友好度之間的一種折中。

回到題主的問題。

對於進程間通信,如果採用嚴密的協議格式,也就是題主說的結構化數據,那麼無論是用二進位表示也好,還是用字元串表示也好,精準度都是能夠得到保證的。

二進位表示可能效率高一些,但是可讀性和跨平台兼容性可能不太好。而採用字元串方式表示則相反。

但是如果所有的地方,即使是一些非常簡單的場合,都強制使用嚴密的協議格式,那可能開發人員又會不太樂意了。


在程序之間傳遞數據,乍一看只有數據的發送方和接收方對這個「數據」感興趣,似乎只要發送方和接收方能夠處理的了就可以了,對於處理效率有一定要求的程序,傳遞結構化數據就是一個讓程序能更高效的發送、接收、處理、反饋數據的有效手段,這也是結構化數據的優勢所在(因為單位體積的結構化數據的信息量大嘛)。

但是只要我們仔細想一想,現實情況下,還有一個「第三方」對這個「數據」同樣感興趣,那就是寫這部分代碼的人類,但是人類能夠高效的分析、處理問題(在這裡就是編寫、調試、維護程序了)的方式和計算機區別比較大。計算機優勢在於運算速度,人類的優勢在於理解之後對未知問題的分析(相比電腦,人類應該比較適合處理單位體積的信息量不那麼大的非結構化數據)。

正是由於人類和計算機又需要配合,二各自的優劣又很不一致,才會產生持久的爭論:

究竟是使用結構化這種讓計算機執行效率提高但人類理解效率降低的數據傳遞方式,還是使用字元串這種讓計算機執行效率降低但人類理解效率提升的數據結構傳遞數據

所以我個人的建議是:

進行介面設計時,首先從讓人「容易理解」的數據傳遞形式出發。

因為經過這麼多年的軟體開發的實踐,我們都知道關於軟體工程師的諸多夢魘都來自於軟體的調優、DEBUG和維護階段。所以設計階段,讓程序之間的介面對軟體工程師友好一些(這裡指的是介面數據結構更易理解)會明顯提高程序的整體開發效率和質量。

最後說一句,單純比較「結構化數據」和「字元串」這兩種數據傳遞方式是不可能有標準答案,這個問題適合具體問題具體分析,但不適合泛泛而談。就像沒有人能籠統地回答「一個人究竟是說中文好,還是說英文好」一樣。


顯然更合理。不過這裡並不要求說你一定要在程序的邊界上傳遞結構化數據,只要你在API的邊界上傳遞的是結構化數據,而且序列化不會產生歧義就可以了,譬如強類型圖 &<--&> XML。


字元串也可以是結構化數據。既然提問者把數據化結構和字元串對立起來,那說的的結構化數據只能是狹義的結構化數據:即已經無需 parsing 的 in-memory 數據(對於數和圖型數據),或者高度對齊的 fixed-width-field 數據。

先說 in-memory 數據。不能跨越物理內存空間。再說 fixed-field 數據,雖然省去 parsing,但是每次做擴展都要重新寫通信雙方的大量代碼。

二者都不利於調試。也不利於工具鏈的打造。

有時候,不用細說,把問題涉及的對象分分類,你就自己看出問題了。


我覺得不需要。程序間的通信因為需求的不同,結構化數據的差異可能會很大。把邏輯層面的東西放進os的設計里未必是件好事。當然,王垠一直認為這是好事。個人覺得消息的解析用類似protobuf這樣的工具就可以了。不同的工具可以使消息解析更加靈活。


其實就是因為應用程序間難以遵循統一的協議,各種程序的輸出格式一多,自然而然大家都用兼容性最好的純文本了。換句話說,如果人類在剛進化的時候就有了計算機,現在人與人之間的交互說不定就是走 Protobuf 了,想想就激動…


使用不能可靠地反序列化的字元串格式是不合理的,比如UNIX下用awk、sed這些工具匹配上下游的輸入/輸出流註定會導致bug層出不窮


這個問題得從兩個角度來看,如果是進程內通信,函數與函數的調用那麼顯然是結構化數據更合理,一來有利於調式和規避一些潛在的類型帶來的邏輯上的錯誤再一個有利於索引和優化(排序之類)。

如果跳出這個範疇,上升到IPC或者異構系統間的通信,那麼作為最通用的數據結構字元串的優勢就顯現出來了。http,ftp,smtp,soap等等幾乎所有叫的出來的通信協議都是基於字元串的。


給樓主舉兩個例子

HTML作為伺服器和瀏覽器之間的通訊格式,是基於字元串的

Java的Bytecode內容完全可以字元串化,但設計者選擇了位元組碼

這兩個規範都是經過仔細考慮後制定的,並且都取得了極大的成功


因為字元串需要 parse/serialize , 這些會帶來額外開銷。


推薦閱讀:

在循環語句中,for(i=0;i<n;i++)和for(i=0;i<n;++i)有什麼區別?
編寫彙編代碼最好的IDE是什麼?
做了很久的項目,結果代碼全沒了是一種怎樣的體驗?
在 GitHub 可以做什麼,用戶又習慣做些什麼?
如何看待「初學者把自己新寫或寫的爛的項目放到 GitHub 就是浪費公共資源,給中國人丟臉」的言論?

TAG:編程 | Linux | 計算機 | 代碼 | Unix |