-
1 # 編碼那些事
-
2 # 皮皮魯的科技星球
計算機只能執行二進位制程式碼
也許你已經知道,計算機是基於二進位制執行的。就像道家哲學的陰陽一樣,計算機只有兩個狀態,開或關、真或假、1或0…因為,組成計算機的基本元件——半導體只能以二進位制進行計算。我們程式設計所用的C/C++、Python、大資料、AI等層出不窮的技術,以及我們儲存在電子裝置的文字、音訊、影象、影片等媒介,最終都是以二進位制的形式,被計算和處理的。計算機體系最底層的工程師要使用二進位制程式碼控制晶片來做計算和處理。
我在我的Mac上編寫了一個名為的程式,其二進位制和彙編程式碼如下所示:
首行的表示這是一個可以執行在64位x86架構的處理器上、基於Mac OS的一段程式。不同的計算機晶片廠商所設計的半導體電路不同,在晶片上程式設計的二進位制規則不同。執行同樣的一段的邏輯,在基於ARM架構晶片的Android手機上所需要的二進位制程式碼與上面展示的會截然不同。當前市場上計算機CPU晶片基本被幾大科技公司壟斷,除了剛提到的Intel和AMD研發的應用在個人電腦上的x86-64處理器,應用在手機、平板電腦等移動裝置上的ARM架構處理器,還有應用在大型伺服器和超級計算機上的IBM Power系列處理器等。不同架構的CPU處理器都有自己的一套指令集(instruction set architecture,簡稱ISA),這就像一個設計圖紙和使用說明書,告訴程式設計人員如何使用在其晶片上進行程式設計:包括如何進行加減乘除計算,如何從記憶體中讀取資料等指令操作。底層開發人員會根據不同指令集,適配不同的CPU處理器。計算機能執行的指令,又被成為機器語言或機器碼。
前面所展示的二進位制檔案是一個。什麼是可執行檔案呢?可執行檔案就是二進位制機器語言的集合,可以被機器執行,得到我們想要的結果。我們在Windows上常會遇到的檔案,就是可執行檔案,其實是的縮寫,從手機應用商店下載的APP也是可執行檔案的一種變體。
C語言從原始碼到可執行檔案很多朋友覺得C/C++程式設計除錯難,沒有比較就沒有傷害,看到前文所提到的一個簡單加法的程式竟然需要這麼多看不懂的01程式碼,是不是覺得C語言簡直是天才般的發明。是的,C語言的發明者當時考慮的就是不同晶片廠商有不同的指令集,相互之間難以相容,於是想在那些晦澀難懂的底層語言上,建立一個更為通用的程式設計正規化,這樣程式設計人員不用浪費時間精力去識記大量的01二進位制指令。那C語言程式碼是如何轉化為可被機器執行的二進位制檔案呢?編譯器和作業系統是兩個非常關鍵的技術。
下面繼續以加法計算原始碼為例,展示編譯器和作業系統計算機將C語言轉化為機器可執行檔案。
Linux和Mac OS使用者可以使用這個命令來將的原始碼編譯成名為的可執行檔案,會生成在當前的資料夾下。
執行這個二進位制檔案,結果將被列印到螢幕上:
是一款開源的編譯器,是GNU Compiler Collection中的一員,它可以將C語言程式碼編譯成可執行檔案。GNU Compiler Collection還有C++編譯器、Fortran編譯器,並且支援包括x86-64和ARM在內的不同指令集。
C語言從原始碼到執行,要使用編譯器來編譯(compile)、彙編(assembly)並連線(link)所依賴的庫,形成機器可執行檔案。執行這個二進位制檔案時,作業系統會為程式分配記憶體和CPU資源。“編譯”和“彙編”,相當於將C語言翻譯成底層語言。另外,程式碼中使用了庫函式,當我們使用別人寫好的函式時,需要將這些前人寫好的庫函式連線到我們的可執行檔案中,否則會呼叫函式失敗的錯誤。我們將這種需要編譯的語言稱為編譯型語言。編譯型語言有C/C++、Fortran等。
作業系統和編譯器是緊密相連的,不同作業系統所提供的編譯環境不同。Linux和GCC編譯器密不可分,Windows有自家研發的MSVC(Microsoft Visual C++)。不同作業系統在管理網路、讀寫硬碟、圖形化等具體的實現方式不同,庫函式連線方式不同…可執行檔案一般需要呼叫這些作業系統介面,所以最終連線生成的可執行檔案會截然不同。瞭解了編譯知識,就不難明白為什麼很多軟體提供商對同一個軟體會提供Windows、Mac OS、Linux、iOS、Android等多個版本的下載。因為不同平臺的硬體、編譯器和作業系統存在著巨大差異,可執行檔案完全不同。所以,也就不難理解Windows軟體為什麼不可能在Mac OS上執行。
實際構建一個大型專案時,編譯要考慮的問題會更多。比如我自己編寫了多個檔案,檔案1會被檔案2呼叫,所以要先編譯檔案1,後編譯檔案2,否則會因為順序顛倒而報錯;還比如編譯型語言對所以依賴的庫函式非常挑剔,如果版本過低,有可能出現編譯錯誤。類似的問題會很多,因此編譯型語言在程式設計和除錯時更麻煩,實際操作中一般會使用構建工具鏈(toolchain),根據一定的順序,從前到後串起來地去編譯。
解釋型語言:Java、Python、R…
既然可以將01組成的機器語言抽象成容易編寫的C語言,那為什麼不能繼續再用類似的辦法,再做一次包裝呢?IT圈的一句名言就是:計算機科學任何領域的問題都可以透過增加一箇中間層來解決。一些大牛忍受不了C語言這樣編寫和除錯太慢,系統平臺之間無法共享移植的問題,於是開始自立門戶,建立了新的程式語言,最有名的要數Java和Python,這類語言不需要每次都編譯,因此被稱為解釋型語言。matlab、R、JavaScript也是解釋語言。
解釋型語言一般是使用C語言等偏底層的語言做一個或者,程式設計人員需要先在自己的計算機上安裝這個直譯器,接下來就只用關心自己的原始碼,其他的事情都交給直譯器去做。如果把編譯型語言的編譯過程比作將原始碼“翻譯”成機器語言的話,那麼解釋型語言就是同聲傳譯。編譯型語言是一篇提前就“翻譯”好的稿子,拿過來就能被讀出來,這樣肯定更快;解釋型語言要等翻譯邊“聽”邊“翻譯”,速度當然慢很多。
不同程式語言的效能測試 - https://julialang.org/benchmarks/
C語言和相應編譯器經過了幾十年的發展,在效能最佳化上已經達到了極致,一般是所有高階語言中速度最快的。上圖展示了一個對不同程式語言在不同任務上的測試,資料以C語言為基準,可以看到Python、R等語言在部分任務上要比C語言慢10倍到100倍。Julia語言是解釋語言中的“奇葩”,它剛剛誕生沒幾年,語言的設計上使用了更多新技術,屬於長江後浪推前浪了。
有了直譯器,我們可以在任何安裝了Python的機器上運行同樣一份原始碼檔案。像Python這樣的解釋語言就像一個高階計算器,非常容易上手,有一些理工基礎的朋友,半天時間就能學會。
其實,這就是一個妥協的過程,解釋語言放棄了速度,取得了易用性和可移植性。
如果我還是關心速度呢?當然還是要回歸底層,拒絕中間商賺差價嘛!
以Python為例,為了保證效能,大部分高效能科學計算庫其實都是使用編譯型語言編寫的。比如,感興趣的朋友可以前往numpy的原始碼地址(https://github.com/numpy/numpy)檢視,會發現很多C語言編寫的程式碼。對於一些計算密集型的函式和方法,Python使用者自己可以使用這樣的工具,R語言可以使用。我最近在使用Java的jni來呼叫C++程式碼,發現速度有成倍提升。
另一種方案是JIT(Just-In-Time)技術。JIT把需要加速的程式碼編譯成了機器語言,不再需要“同聲傳譯”拖累自己了。我在Python上用庫進行過JIT測試,同樣的程式碼會有8倍以上的速度提升。
我以後也會在我的專欄中介紹如何對解釋語言進行加速。
-
3 # 天觀易3階控制論創新
二樓的還未消化。故乾脆搬進來天天細讀,那末把易經傳統看成巨型二進位制轉換器處理萬事萬物萬變萬,直切入陰陽量子計算機系統,很贊同二樓主的比喻。計算機是基於二進位制執行的。就像道家哲學的陰陽一樣,計算機只有兩個狀態,開或關、真或假、1或0…因為,組成計算機的基本元件——半導體只能以二進位制進行計算。我們程式設計所用的C/C++、Python、大資料、AI等層出不窮的技術,以及我們儲存在電子裝置的文字、音訊、影象、影片等媒介,最終都是以二進位制的形式,被計算和處理的。計算機體系最底層的工程師要使用二進位制程式碼控制晶片來做計算和處理。
-
4 # TonyDeng
掌握一門編譯型語言和解釋型語言是比較好的感知方式,那樣會知道兩者是互補的,沒有誰比誰更優越。區別和異同,自己實踐過才理解深刻,光說你也未必信。
回覆列表
1、編譯型語言
編譯型語言字面意思就是,編譯的時候直接編譯成機器可以執行或呼叫的程式(如exe、dll或ocx等型別)。典型常見的編譯型語言包括C、C++、Pascal等語言。如將C語言可直接編譯成exe程式,執行時直接執行exe程式就可以了,無需重新編譯,所以程式執行效率較高。編譯型語言程式執行過程如下所示:
2、解釋型語言
解釋型語言是相對於編譯型語言來說的,其特點是不需要編譯,執行時使用一個專門的直譯器去翻譯,每一條語句都是執行的時候才翻譯,所以這類程式每執行一次就要翻譯一次,執行效率較稱低。典型的如Java、Python、Matlab等語言,都屬於解釋型語言。解釋型語言程式其執行過程如下所示:
3、兩者比較
從執行效率上來說,編譯型語言執行速度快;而解釋型語言程式碼需要有專門的直譯器,在程式執行時,除要給使用者程式本身分配記憶體空間外,直譯器也佔用系統資源,所以其執行速度較慢。
從可移植性上來說,編譯型語言需要經過編譯方可執行,只能在相容的作業系統上執行,故可移植性差;解釋型語言可移植性好,只要有直譯器環境,程式就可以在不同的作業系統上執行。
從程式碼保護性上來說,編譯型語言編譯後程序不可以修改,且看不到原始碼,保密性較好;而解釋型語言較容易看到原始碼。
從應用場合來說,編譯型語言由於其執行速度較快,同等條件下對系統的要求較低,因此常用於開發作業系統、大型應用程式、影象處理、資料庫開發等場合;解釋型語言常用於,一是對執行速度要求不高(如一些網頁尾本、伺服器指令碼、介面輔助開發等)的場合,二是對跨平臺(作業系統的相容性)有要求的場合。