多語言協作-作業系統級上應用面向物件方法的一個簡單例項
為什麼要多語言混合程式設計
答案很簡單:
- 每種語言各有所長,各有所短,計算機世界同人的社會一樣,合作才是王道。
- 合作才能取長補短,提高程式設計和實現的效率。
C擅長於底層,高明於效率;JAVA是網路開發的不二之選,Python程式設計簡單,各種應用包很多,便於快速構建應用,但計算效率稍遜,MATLAB則有利於數學演算法的原型驗證,但閉源、龐大,難於直接用於工程。R語言專於統計,Julia是個新秀,也是集Python,R,MATLAB之優點,而又具C之計算效率的新型語言,但相對演算法包還少。Octave與MATLAB幾乎相同,程式碼相容,只是缺少MATLAB的各種工具箱和專用函式,但在資料計算領域也是相當出色的。存在就是合理–德國哲學家黑格爾說: “凡是合乎理性的東西都是現實的; 凡是現實的東西都是合乎理性的。(黑格爾《法哲學原理》序) 。在計算機的世界裡,也是如此,只不過規則比現實社會簡單了許多。
混合程式設計的三種境界-親密的,世俗的,商業的
用現代社會的合作與分工模式看待和解決計算機系統中多語言的協作問題,大致是沒有錯的。問題是要解決如何合作,在哪一個層次上合作,遵循哪些合作的規則,如何制定對合作失敗的備選解決方案等等諸多難題。
親密模式(非面向物件的模式)
- 語言層面上的合作:這是在語言級上相互呼叫的問題,也是通常意義上的混合語言程式設計。例如,在Python中呼叫C,在JAVA中呼叫MATLAB等等,這是最深最緊的合作,是“朋友加兄弟的關係”,戰鬥的友誼如是鮮血凝成的,當然也會付出鮮血的代價! 一榮俱榮,一損俱損。各種語言都有或者通過第三方設計著自己的合作方法,介面,但我不主張用這種方式。最主要的原因是:這是一種緊耦合模式。其二,對程式設計師的知識要求太高,導致程式設計和後期維護成本都高。 其三,擴充套件性不好。反正緊耦合模式的所有缺點都是這種方式的缺點。愛得越深,傷得越重,----過於親密的關係將導致撕裂時的血肉模糊。這是一種談感情傷錢
世俗模式(中小規模面向物件的模式)
- 在作業系統層面上的合作:所有程式都跑在一個作業系統上,就象人都在同一個社會文化中生活,必須要遵循社會活動和相互關係的規範,即道德、風俗和法律;在計算機中,就是作業系統所維護的規則,訊息傳遞 的方法以及排程協議等。只要作業系統不死,單獨一個程式或功能是可替代的,就是常說的:離開了誰,地球照樣轉,所以,這是一種較為穩定的合作模式。因為這是在一種作業系統級上的面向物件方法:不同語言編寫的應用程式自己是封裝
商業模式(大規模面向物件的模式)
- 在網路層面上的合作:這對應於社會生活的國際合作,必須遵循普世的價值觀念,突破文化的障礙,相當於在計算機網路世界中不同作業系統上執行程式的合作:大家都以服務的模式進行資料交流好了。網路層面上的合作是最鬆耦合的,從而也是最Robust的。適合於更大型的分散式場境。TCP/IP及建立在其上的應用層協議是網路程式合作的基礎。
本文只討論中間一種模式:即在同一個作業系統下,在作業系統層面上的多語言混合程式設計問題。
例項
例如,我們要完成的任務是:與外部系統或網路中取得資料,對資料進行復雜計算或處理,視覺化,將視覺化結果以服務方式提交使用者。我們用:
- C 語言程式碼來寫資料獲取程式;
- Octave(相容MATLAB的開源科學計算環境)來實施具體計算;
- Gnuplot工具來輸出結果圖。
以濾波器頻率幅度響應為例項,設濾波器傳遞函式的分子分母系數為:
b=[0.0563 -0.0009 -0.0009 0.0563]; 分子係數
a=[1.0000 -2.1291 1.7834 -0.5435]; 分母系數
以下在Windows 10下實驗。MATLAB程式為:
b=[0.0563 -0.0009 -0.0009 0.0563];
a=[1.0000 -2.1291 1.7834 -0.5435];
[h,w] = freqz(b,a,1024);
plot(w/pi,abs(h));
執行結果:
用Octave執行,結果一樣:(直接命令列啟動Octave-cli.exe)
任務很簡單,完全不必要多語言程式設計完成,所以這裡只是用來展示多語言程式設計的方法和過程。
為了從Octave中輸出資料(而不是畫圖,一般計算程式不應負責視覺化互動,在除錯過程中除外),我們用fprinf函式取代plot函式。寫成:
fprintf("%e\n",abs(h));
將Octave所在的路徑新增到系統path路徑中,將MATLAB程式碼寫為檔案freq.m :
【注:Octave下,副檔名,m
不是必須的,可以是任意副檔名,無副檔名也行。】
b=[0.0563 -0.0009 -0.0009 0.0563];
a=[1.0000 -2.1291 1.7834 -0.5435];
[h,w] = freqz(b,a,1024);
fprintf("%e\n",abs(h));
然後通過命令列以Octave呼叫來執行freq.m
指令碼:
C:\> octave-cli.exe freq.m
...(前略,共1024行)
8.593363e-04
7.638517e-04
6.683682e-04
5.728854e-04
4.774034e-04
3.819220e-04
2.864411e-04
1.909605e-04
9.548020e-05
C:\>
還可以通過管道命令執行指令碼(這是程式間資料能互動的關鍵!):
type freq.m | octave-cli.exe
就會在螢幕上打出計算結果資料來。而用重定向
type freq.m | octave-cli.exe > freq.dat
則生成了資料檔案。最後,在gnuplot中,用命令
gnuplot> plot "freq.dat" u ($0/1024):1 w l
即得結果:
我們也可在gnuplot中直接執行管道指令,就可避免寫資料檔案。即:
gnuplot> plot "<type freq.m | octave-cli.exe" u ($0/1024):1 w l
所以,只要C程式碼程式能輸出與<type freq.m
相同的字串,就可以通過管道直接送到Octave中執行了,而執行結果又可通過重定向存入資料檔案中供作圖程式使用。
最簡易(也是最土的,無實用處的)C程式碼如下:
//freqdemo.c
#include <stdio.h>
int main(int argc, char *argv[])
{
puts("b=[0.0563 -0.0009 -0.0009 0.0563];");
puts("a=[1.0000 -2.1291 1.7834 -0.5435];");
puts("[h,w] = freqz(b,a,1024);");
puts("fprintf(\"%e\\n\",abs(h));");
return 0;
}
【注意】其中puts("fprintf(\"%e\\n\",abs(h));");
的寫法。
編譯並執行:(用Tiny CC的 tcc.exe
編譯)
C:\Octave\Octave-4.4.1\bin>tcc freqdemo.c
C:\Octave\Octave-4.4.1\bin>freqdemo.exe
b=[0.0563 -0.0009 -0.0009 0.0563];
a=[1.0000 -2.1291 1.7834 -0.5435];
[h,w] = freqz(b,a,1024);
fprintf("%e\n",abs(h));
C:\Octave\Octave-4.4.1\bin>
於是,用管道命令就寫成了:
freqdemo.exe | octave-cli.exe
然後,編寫gnuplot指令碼freq.plt
set term png
set output "freq.png"
plot "<freqdemo.exe | octave-cli.exe" u ($0/1024):1 w l
set output
執行之:
C:\Octave\Octave-4.4.1\bin>gnuplot freq.plt
則直接生成了png圖片:freq.png
,如下
程式執行過程解釋如下:
- gnuplot 啟動,呼叫執行指令碼
freq.plt
- 依據plt指令碼,設定輸出為png圖片,並定下檔名為
freq.png
- 執行作圖語句plot
- 在plot中,首先執行
freqdemo.exe
,其輸出通過管道符|
送octave執行。Octave 收到freqdemo.exe
送來的字串後,當作程式碼解釋並執行,輸出資料到控制檯。再由<
重定向回gnuplot程式。 - plot收到資料後,按引數
u ($0/1024):1 w l
執行繪圖並寫png圖片。 - 執行指令碼後成功退出,並不顯示任何資訊,這符合Unix系統沉默是金是設計哲學。
C:\Octave\Octave-4.4.1\bin>gnuplot freq.plt
C:\Octave\Octave-4.4.1\bin>
利用這種方法,可以呼叫任何語言編寫的可執行程式或指令碼,從而實在在作業系統級的功能組裝。組裝者無需關注各功能的具體實現,只要各功能程式提供完整的執行方法和測試報告即可。
繼而,還可以通過CGI(公共閘道器介面:Common Gateway Interface)或更高階的Java Servlet來向web伺服器提供互動,形成web服務,作為網路級服務整合的原子服務,參與到大規模面向物件的模式的網路層面的合作中去。