1. 程式人生 > >編譯器與直譯器的區別

編譯器與直譯器的區別

為了讓更多的人能夠從本質上理解編譯器和直譯器的區別,我杜撰了一個小故事

來福與旺財的養牛場

來福和旺財有一 個養 牛場。本來養牛不是一件太難的事情,但是偏偏他倆養的牛都有特別的怪癖。奶牛阿圓只吃切成圓形的牧草,而奶牛阿方和阿三(印度來的?)分別只吃切成正方形 和三角形的牧草。如果來福和旺財拿不和奶牛性格的草去餵食,阿X們不但不產奶而且還會鄙視來福和旺財。

於是來福和旺財分別有了自己的主意

來福的方案:
來福發明了三套大型碾碎機:圓圓碾碎機,方方碾碎機和三三碾碎機。每天收割了牧草,就分別放到這三套機器裡碾碎給三頭奶牛吃。但是一旦被碾碎了,這堆草就只能給某一頭牛吃了。很明顯阿方是不會吃給阿圓準備的草的。而且來福每天都要操作這三臺機器,覺得比較麻煩。
點選在新視窗中瀏覽此圖片




旺財的方案:
旺財在考察了來福的方案後,發現每天操作三臺機器真的很麻煩,而且有時有的牛吃不完,有的牛不夠吃時,還不能在奶牛之間調配碾碎了的牧草。所以旺財有了不同的想法:口罩型碾碎機。
點選在新視窗中瀏覽此圖片 

就像在圖上看到的,旺財給每頭奶牛裝配了一臺口罩碾碎機,所以三頭牛完全可以在一個槽裡吃草了,在吃之前口罩會自動把牧草碾碎成適合該牛食用的型別。旺財就輕鬆了,他每天只需要割割草就行了。

但是旺財被鄙視了???

是的,被來福鄙視了。來福觀察後發現,旺財的口罩碾碎機的效率很低(因為比較小嘛)。阿圓食量大,吃來福的圓圓碾碎機的食物一個小時就飽了,但是戴著口罩吃的時候要吃十個小時!所以來福認為旺財的口罩碾碎機雖然省事,但只能喂喂小牛,完全不適合食量大的牛。

旺財也覺得這樣做有問題,但他不想回到來福方案上,他改進了口罩方案:牧草預切割機。
點選在新視窗中瀏覽此圖片


呵呵,看到預切割做了什麼嗎?它把牧草割得小了一些,所以需要口罩碾碎機做的事情就少多了。(當然口罩碾碎機也要作適當改進適合預切割後的牧草,所以圖上用藍色表示)阿圓以前用口罩不是要吃十個小時嗎,現在兩三個小時就可以了。

編譯器與直譯器

好的,謝謝你有耐心看到這裡,經過上面那個不太恰當的例子,相信你已經相當的糊塗了。那麼我們試著回到技術方面來。
在上面的例子中
牧草 = 我們的各種程式語言,C/C++/C#, Java, Pascal, PHP, Python, Perl, Java Script等等
切割機 = 各種編譯器
奶牛 = 各種CPU(不要告訴我Intel和AMD哦),比如x86,ARM,MIPS等等
那你應該知道了為什麼奶牛會有吃不同形狀牧草的嗜好了,這個奇怪的比喻是為了表示不同的CPU接受的不同的機器語言。

對應上面的奶牛圖,編譯器的圖是這樣的
(本圖是我重新畫的)


原始碼被編譯成機器碼,在CPU上執行。

而直譯器是這樣的
點選在新視窗中瀏覽此圖片


用直譯器很方便,只需要直接“執行”就好了,不用像C那樣有編譯連結的工序。

為什麼說這些語言是跨平臺的?因為你寫了程式以後,如果這個平臺上有這種語言的直譯器,只需要拿到這個平臺上直接執行就可以了。你可以理解為:直譯器是在“一邊編譯,一邊執行”,它只是把以前程式設計師手工做的編譯過程放在了執行程式的時候進行。

為什麼我們一般說直譯器的效率比較低?你也可以想象的是,一段程式在直譯器中執行時可能會被編譯多次,因為每次執行到這段程式時,都會重新編譯一次,這樣的開銷是很大的。

所以誕生了Java,C#這樣的預編譯語言:
點選在新視窗中瀏覽此圖片

在執行之前,需要手動把原始碼編譯成中間程式碼(Java裡叫位元組碼),然後在直譯器中執行。
這種架構避免了上面純直譯器中編譯原始碼的開銷,所以相對會有效率一些。

但 是我不能騙你們,其實我畫在純直譯器中的Python,Perl,PHP可能都不會是真的純解釋執行的,這樣實在是太沒有效率。Python在執行時會生 成pyc的二進位制臨時檔案,看起來很像是預編譯的結果。只有JavaScript這種真的不會寫得太長的語言(Ajax請原諒我)才會採用純解釋的執行方 式。