天天看點

【問道】計算機er要掌握的計算機思維

作為一個計算機人同時也面試過很多畢業生,不得不談的就是計算機思維和對計算機整體的了解。計算機領域發展到現在語言、架構層出不窮,但是計算機思維和底層是不變的。我來談談我對計算機的了解,希望通過本文你可以建構計算機思維,底層并不困難,架構也并不高深,希望可以給你一些思考和幫助。

導讀:《大學》裡面有一句話'物有本末,事有終始。知所先後,則近道矣' 。什麼意思呢,每樣東西都有根有枝,每件事情都有始有終。明白了這本末始終的道理,就接近事物發展的規律了。那麼我們思考計算機有沒有本末始終的規律,答案是有的,本文将通過計算機系統底層(組成原理、體系結構、彙編原理、彙編語言、intel開發手冊、CSAPP、C++等)的一些書籍,幫助我們正确、高效掌握計算機思維。

【問道】計算機er要掌握的計算機思維

易有太極,太極生兩儀

易經中有這樣一句話'易有太極,太極生兩儀 ',了解為所謂太極即是闡明宇宙從無極而到太極,以至萬物化生的過程。計算機也不例外,經曆從無到有從1936年艾倫・圖靈提出的一種抽象的計算模型,将人們進行數學運算的過程進行抽象,由一個虛拟的機器替代人類進行數學運算,我們稱之為圖靈機。到馮諾依曼提出計算機的體系結構,從此往後不管是最原始的、還是最先進的計算機,使用的仍然是馮·諾依曼體系 最初設計的 計算機體系結構。

【問道】計算機er要掌握的計算機思維

開天辟地,太極生兩儀 - 從圖靈機到馮諾依曼體系

那麼馮諾依曼體系就引出了計算機體系結構,我們翻開《計算機體系結構精髓》一書中描述了,這個子產品應該去了解的知識有數字邏輯(電壓、半導體等等)、處理器的基本原理、操作數與指令、大量篇幅描述了CPU、存儲器和總線等,那我們總結就是馮諾依曼體系中的4大組成(運算器、控制器、存儲器和輸入輸出)。

【問道】計算機er要掌握的計算機思維

二生三,三生萬物 - 馮諾依曼體系與計算機體系結構

既然如此我們看下現在計算機都有哪些組成,宏觀上也就是 計算機的視角,我們打開電腦能考到的就是鍵盤滑鼠這類的外設(輸入輸出),計算機内部是CPU(運算器+控制器)、記憶體和磁盤(存儲器);微觀上,CPU内部視角,有寄存器(MU)和主存、運算單元(AU)、控制單元(CU)幾個子產品,這些子產品顧名思義寄存器=存儲器、主存=輸入輸出(因為要與CPU外部互動)、運算單元=運算器、控制單元=控制器。

【問道】計算機er要掌握的計算機思維

現代計算機組成

這裡僅僅是了解計算機和CPU與馮諾依曼體系的關系,如果了解困難,我們可以換個角度,在我們進行軟體開發時的MVC架構,View=輸入輸出、Controller=運算器+控制器、Model=存儲器,這樣是否可以了解馮·諾依曼體系的神器之處了呢?

【問道】計算機er要掌握的計算機思維

馮諾依曼體系與現代計算機、CPU的關系

至此我們算是初步淺識了計算機的整個底層,并且知道了CPU是計算機的核心(運算+控制),因為我們并沒有深入到CPU(寄存器)、記憶體(資料記憶體、指令記憶體)等等。

物有本末,事有終始。知所先後,則近道矣

作為一名程式員,光有底層的邏輯還不夠,還要建立完整的代碼到編譯到執行的思維,也就是所謂知其先後,我們寫的代碼究竟是如何操作上述硬體的?我們知道根據馮諾依曼體系,計算機隻能識别 0 1 的代碼諸如00000101,是以我們開始往上推,人類是不可能去寫這個東西的,人類隻需要将0101的代碼對應上即可,但是不管是熟知C語言還是Java都不能直接變成0101的代碼,那麼一定是中間有一系列什麼東西做了将進階語言轉化為機器語言的步驟(編譯器->彙編器)。

于是出現了ISA彙編指令集,在《計算機組成原理》中有詳細讨論,這裡我們了解為,将驅動控制CPU的代碼封裝成特定的指令集,由CPU廠商去做代碼的開發,用來操作控制單元,将存儲單元中的資料放入計算單元,将計算結果傳回給存儲單元。

【問道】計算機er要掌握的計算機思維

ISA操作CPU的過程

那麼有了彙編指令集,諸如Java、PyThon、Go語言等還是不能直接操作ISA指令集的,我們還需要一個能把左右語言 編譯 成統一的彙編語言(編譯器),再去調用彙編代碼的過程。将進階語言翻譯成彙編語言或機器語言的過程,就是《編譯原理》了,然後彙編語言操作CPU,去控制其他硬體完成操作(操作CPU的控制單元、控制存儲單元,運算單元對緩存的資料進行操作)。

【問道】計算機er要掌握的計算機思維

編譯原理

小結: 至此我們得到了一個所有語言共同的編譯運作模型和計算機體系模型,簡單建構了ISA彙編指令集與彙編原理的了解。

【問道】計算機er要掌握的計算機思維

從代碼到硬體的過程

君子之道,辟如行遠必自迩,辟如登高必自卑

《中庸》裡 '君子之道,辟如行遠必自迩,辟如登高必自卑 ',翻譯過來就是 君子的中庸之道,就好像是走遠路必須從近處開始,就如同是登高必須從低處開始。 經過上述兩講我們知道了計算機體系結構和代碼編譯的過程,但是都僅僅是最簡單的了解,現在我們開始登山!

一、惟茲何功,孰初作之?——計算機組成原理-ISA和CPU處理指令原理

上述說到控制計算機,需要控制CPU,而ISA操作CPU,進而操作其他的一切,ISA 是一個集合,那麼就一定有多個内容,我可以 控制CPU幹什麼呢?是以機器指令會存在很多個 ->  我怎麼識别誰是誰 ?->  是以機器碼根據CPU廠商給定的規則(ISA),彙編器 按照這個規則将01放入規則指定的位置即可,實際上不管指令多麼神奇,終究還是資料是代碼,就需要容器去操作需要記憶體去存儲。下圖CPU記憶體模型。

【問道】計算機er要掌握的計算機思維

CPU記憶體模型

指令操作的資料最終都會在記憶體,是以按照功能将記憶體存放資料的區域切割即可:指令段私有的資料(棧)+指令段共享的資料(堆) -> 指令段可能又有多個,那麼就代表我可以 call 多個指令 -> (堆棧)資料結構來表示這種存儲關系。其中,指令流動态配置設定的私有資料,分為棧頂棧底寄存器,由于記憶體是連續的且有高低之分,按照棧記憶體的增長方向可配置設定記憶體。指令流動态配置設定的共享資料稱為堆記憶體。在彙編代碼的 .data段定義的資料是資料記憶體。指令記憶體,存放指令而又由于指令中可以寫入資料(mov 1,寄存器),是以又存放了資料,隻不過這個資料嵌在指令中。

說了這麼多,是想告訴讀者,每個指令流都有自己的棧幀,棧幀裡面儲存目前指令流操作的資料,當使用cell指令,轉移指令流後。隻需要儲存上一個棧幀的棧底。是以我們的程式中,棧記憶體 就可以了解為多個指令流私有的資料;堆記憶體 是多個指令流共享 的資料(動态資料);代碼段記憶體 是 儲存程式的指令流;資料記憶體是儲存程式資料(編譯時存在的資料靜态資料)。

由此可見底層CPU、OS與JVM的記憶體模型是息息相關的,這裡初步構件對記憶體模型的了解,對于CPU以及寄存器的了解遠不止于此,寄存器、高速緩存、intel手冊等等筆者會放在後續博文中詳細介紹。

二、冥昭瞢暗,誰能極之?——再探編譯原理與彙編語言

上述說道編譯原理是将進階語言翻譯成彙編語言或機器語言的過程,編譯的過程有一個三明治(三層)架構——前端、中間結構、後端。前端是由不同需要接入目前編譯器的前端開發者進行開發,來适配多門語言,中間結構會産生一個叫IR的中間語言解耦,後端由不同需要接入目前編譯器的後端開發進行開發,來适配多門目标機器語言(ISA)。中間的細節類似于我們做英語翻譯分析語言的文法語義,生成中間語言,最後轉化為目智語言,可以參考Java語言的編譯過程,java源代碼->通過javac指令編譯成位元組碼,這個位元組碼就是相當于 IR中間語言。這裡面JIT(即時編譯器)實作了編譯原理的前端和後端,隻不過在記憶體中動态對語言進行編譯;用一門語言(IR)對其他語言進行解釋,執行邏輯是解釋器;編譯器是具有前端和後端的整套邏輯,将一個語言(源語言)編譯為目智語言。

【問道】計算機er要掌握的計算機思維

編譯原理與Javac編譯

了解了編譯過程之後,編譯的目智語言我們稱為彙編語言,彙編語言有兩個編碼規則,一個是AT&T,指令形如mov eax 1;另一個是intel公司,指令形如mov 1 eax;(颠倒了)。進階語言會抽象為彙編語言;我們是否可以推理出來,指令段 相當于函數;指令段之間的調用(call指令)類似于方法之間的調用(函數調用);而操作單元的大小抽象為類型系統(基礎類型 byte  short int的記憶體單元為2^n(n>=0),其他類型:結構體(不同規則的記憶體單元)、數組(相同類型的多個記憶體單元));資料位址操作抽象為指針操作。

【問道】計算機er要掌握的計算機思維

指令段1想要指令段2去修改記憶體單元中的值的過程

總結

本篇文章意在帶你建立計算機底層架構的思維和邏輯,從圖靈機、馮諾依曼體系反推 計算機體系結構 和 ISA指令集架構,從進階語言向下遞推編譯器、彙編語言、彙編器 、到機器語言,ISA指令集 閉環。希望通過本文你可以初步建構計算機思維,通過已知可以繼續向更深(寄存器、連結器、解釋器等等)、更高(MVC、DDD、分布式、雲原生等等)的層面延伸推理。

繼續閱讀