在正式開始學習 Linux 操作系統之前,有必要先回顧/學習一下電腦和操作系統的基本知識,為我們在後續的學習中鋪路搭橋,在瞭解電腦一些基礎原理的條件下再去進行學習,理解應該會更透徹一些。我會從一個程式的簡單構成開始,逐步介紹我對電腦工作原理的一些理解,希望能夠給大家做一個參考。由於中間涉及的知 ...
在正式開始學習 Linux 操作系統之前,有必要先回顧/學習一下電腦和操作系統的基本知識,為我們在後續的學習中鋪路搭橋,在瞭解電腦一些基礎原理的條件下再去進行學習,理解應該會更透徹一些。我會從一個程式的簡單構成開始,逐步介紹我對電腦工作原理的一些理解,希望能夠給大家做一個參考。由於中間涉及的知識很多,有些內容我沒有進行深究,存在許多漏洞,因此僅供參考。
1.程式的構成
程式是由什麼構成的?簡單說來,這裡有一個公式:程式 = 數據 + 指令。這是程式員再熟悉不過的了,數據自不用多說,指令就是告訴程式,怎樣操作目標數據,這個“操作”不僅僅是在數據之間進行簡單的運算,而是包含了操作這些數據的一系列行為的集合,比如做兩個數字的加法運算,除了本身的加法這一指令之外,我們還需告訴CPU從哪裡讀取目標數據,以及完成加法操作後將數據放到何處等。
電腦的底層是二進位數據,因此不管是指令還是數據,最終都會以二進位的形式保存。對於CPU,怎麼區分我們傳入的二進位代碼是數據還是指令呢?這就需要不同的線路將數據和指令進行分離。
- 控制(指令)匯流排:用來向CPU傳輸指令
- 數據匯流排:用來向CPU傳輸數據
2.CPU的簡單理解
一個CPU的核心部件包括三個:運算器,控制器和寄存器。
運算器是執行運算操作的地方,它會接收數據的輸入,在內部計算完成之後將數據輸出。
光有運算器還是不夠的,由於我們的指令和數據都是保存在記憶體中,運算器需要知道在記憶體的哪個地方讀取數據,哪個地方讀取指令,以及在計算完成之後將數據放到哪裡等。這些信息就是由控制器提供的。
寄存器是做什麼的?寄存器也叫暫存器,顧名思義,就是暫時保存數據的地方。寄存器位於CPU的內部,用以保存等待處理或者處理過的數據。為什麼需要寄存器?比如我們做一個四則運算,每次運算之後的結果應該保存在哪裡?記憶體嗎?如果將每步運算結果保存在記憶體中,無疑是加大了CPU的開銷,因為要在每步計算完成之後將其放入記憶體中,然後再讀取出來,再輸入到運算器進行計算……這很麻煩,開銷很大,並且浪費了CPU寶貴的性能。寄存器的作用就是將數據暫時存放在CPU的內部,那麼CPU在訪問這些數據的時候,效率將會得到極大的提高(就近原則)。
3.中斷機制(Interrupt)
電腦有很多I/O設備,比如鍵盤,滑鼠,,光碟機,磁碟,硬碟等。如果我們敲擊了鍵盤,CPU怎麼知道我們操作的是鍵盤而不是滑鼠或者光碟機呢?我們可以將敲擊鍵盤這個行為當做一個事件,這個事件是偶發的,CPU如果想偵測到這個事件,有兩個方式可以選擇:
- 輪詢機制(Poll):CPU比較勤快,每隔一段時間就去看看,有沒有發生這個事件,如果發生了,就執行某個操作,如果沒有發生時間,則不做任何處理。
- 中斷機制(Interrupt):CPU比較懶,並不想總是去查看這些事件有沒有發生,而是找另一個人幫忙看著,如果發生了事件,就通知CPU,CPU再去做相應處理。
和CPU一樣,我們都非常勤(lan)快(duo),喜歡輕鬆又有保障的活。對於輪詢機制,有一個問題:事件是有隨機性的,有可能CPU輪詢了一天,用戶並沒有做出任何操作,那不是虧大發了嗎。所以我們肯定會選擇中斷機制啦,事實上CPU採用的也正是中斷機制。
4.中斷控制器
上面說了CPU的中斷機制。那麼問題來了,CPU又怎麼知道是滑鼠還是鍵盤上產生了事件?
這時候中斷控制器就登場了。中斷控制器和CPU的針腳相連,如果把中斷控制器比做蜘蛛,它將通過周圍遍佈的蛛網和電腦上的I/O設備連接,如果某個I/O設備上產生了一個事件,就會發生電信號的變化,這個變化通過蛛網傳給中斷控制器,控制器也就知道是哪一個設備發生了響應,進而將訊息傳遞給CPU。
5.南橋和北橋
對於電腦中的數據處理,有高速低速之分,或者高頻和低頻之分。南橋和北橋就是分別用來傳輸這兩種類型的數據,北橋在物理上距離CPU較進,用來處理高速高頻的數據。大多數的I/O設備都在南橋上,這些設備經過南橋彙總後,通過線路連接傳到北橋,再由北橋傳給CPU。
舉例:一個網頁同時給一百萬個用戶訪問,網頁文件存放在伺服器的硬碟中,伺服器的每次響應都需要從硬碟中讀取這個網頁,由於硬碟連接在南橋,讀取速度和頻率較慢,這會產生嚴重的伺服器延遲(比如一個硬碟最高一次只能進行10萬次的數據輸出,那麼剩下的九十萬用戶就得等著),這是非常搞糟的體驗。因此,現在的伺服器很多都採用了固態硬碟,並將硬碟直接連接在北橋上,以獲取更高的讀取性能。
6.主頻和緩存
主頻可以理解為CPU的計算能力,主頻越大,CPU在單位時間的計算能力越強。CPU的頻率可以達到1GHZ,而記憶體的讀取速度遠遠低於CPU的頻率。給予木桶原理,即使CPU的速度再高,記憶體的讀取效率跟不上,電腦的整體性能也難以提高。為此我們可以造更快的記憶體,但是這種方式造價極高。於是出現了緩存技術,緩存技術是在速度和造價之間的擇中原則。
速度越快的部件,造價越高。因此最快的核心部分,我們只要一小塊,然後在其外圍放性能稍低(相對於核心)造價也稍低的設備,這就是緩存。CPU有一級緩存,二級緩存...緩存在CPU和記憶體之間起到了承上啟下的作用。
緩存的工作,需要遵循程式的局部性原理,程式的局部性原理分為時間局部性和空間局部性。
- 時間局部性:剛剛訪問的數據可能還會被訪問,那麼將該數據需要被緩存。
- 空間局部性:如果訪問一個數據,那麼離這個數據非常近的數據,也應該訪問的比較快。因此在訪問一個數據的時候,把其周圍的數據也一併載入進來,這樣就提高了其周圍數據的訪問速度。
程式的局部性原理,不僅應用在CPU的工作上,也用在碼農的編碼過程中,運用時間局部性和空間局部性,可以顯著提高程式的運行效率。
舉例:
- Javascript中訪問內層變數比訪問全局變數快得多,因此我們在編碼的過程中儘量少的依賴全局變數,可以提高運行的效率。(剋制使用全局變數的好處不僅這一處,這裡簡單的舉例說明)。
- for迴圈中緩存變數,操作資料庫的時候緩存欄位等。
7.機器碼,彙編,高級語言
我們知道所有程式必須要編譯機器碼(二進位)才能被電腦識別和執行,我們也知道彙編是對機器碼的抽象,讓我們不用直面枯燥難懂的機器碼,而使用易於人類的語言進行編程。彙編語言也叫作微碼,是CPU廠商為我們暴露出來,通過微碼我們可以進行針對CPU的編程。需要註意的是,不同的CPU架構不同,對於同一操作,其暴露出的微碼也不盡相同。因此針對不同的CPU,我們需要分別對他們進行編程。儘管有些許蛋疼,但總比使用機器碼編程好太多了。
高級語言是對彙編語言更高的抽象,結合一些額外的機制,來彌合CPU之間的不同。然後暴露出公共的API程式員調用,儘管對於這份API,其在不同的平臺下可能會進行不同的實現,但是對於程式員,我們只需調用這個API,就可以實現平臺的相容,而我們自己再也不用考慮硬體的差異性了。
8.CPU的架構
下麵是一些常見的架構:
- ARM:手持硬體設備(安卓,IOS)
- x86:32位平臺
- x64:64位,來自AMD
- 安騰:來自惠普,Intel收購
- Alpha:惠普
- UltraSparc:SUN公司
- Power:IBM
- M68000:摩托羅拉(M68K)
- PowerPC :IBM
9.CPU怎麼執行一個程式
單核的CPU,在某個時刻只能進行一次運算,為什麼我們的程式看上去是並行執行呢?
這裡需要引入切割機制,切割機制可以分為CPU切割和記憶體切割。
CPU切割:把CPU按照時間片(Slice)切割。比如一個Slice是5ms,那麼每個程式只能運行5ms,下一個5ms就該換一個程式運行了(當然也可能仍然運行這個程式,具體取決於CPU的分配機制)。同時,CPU還應該有一個機制來記錄程式的運行狀態,以便程式在下一次運行的時候可以從先前的狀態繼續執行。
記憶體切割:引入分段機制,想象兩個程式同時運行,而且都從記憶體的某一個編號開始占用(比如0x00000),那麼後面的程式就會破壞掉前面程式的數據。現在引入了記憶體分段的機制,將記憶體分為一塊塊的區域,這些區域內部都從0x00000開始,那麼程式就不會相互干擾了。
10.操作系統
上例中,怎麼保證每個程式在每個時間片中程式都是嚴格執行呢?如果程式賴著不走怎麼辦?
這就需要引入操作系統了,操作系統就是用來對程式進行調度,以及協調其他程式進行工作,是位於硬體和應用軟體之間的中間層。有了操作系統,任何程式都不能直接和硬體打交道,而是要經過操作系統這一中間層進行處理。
同一份程式,在不同的操作系統運行的效果不同的解釋:程式要執行某一個功能,將請求交給操作系統,操作系統通過調用相關的庫來執行,不同的操作系統實現實現某種庫的方式可能不一樣,那麼程式的效果也就不一樣了。
11.Shell
以Windows為例,為什麼雙擊桌面上的圖標就可以運行相應的程式,或則在命令行中輸入calc就可以打開計算器呢?
上面的兩種操作:雙擊圖標和在命令行輸入命令回車,本質上都是指令。我們的指令需要操作系統傳到內核(kernel)中,然後實現程式的運行。接收指令的這個東東,就是人機交互介面(Shell)。Shell包括兩種:
- GUI圖形Shell
- CLI命令行Shell
不管是GUI還是CLI,目的都是向內核傳送指令,實現某項操作,對於內核來說,通過什麼方式傳送指令並不重要。
操作系統內核的功能包括:
- 進程管理(協調)
- 記憶體管理
- 文件系統
- 網路功能
- 硬體驅動
- 安全機制等
12.Linux發行版
終於講到Linux了,照例在此之前應該講講Linux的起源,Unix,Bell實驗室,Apple和Windows等等,但是歷史性的東西並不是這篇博文的重點,這裡就暫且跳過。
Linux是操作系統,也就是軟體,軟體要想運行,就需要編譯成相應的二進位代碼才能運行。
上面我們也談到過,不同的CPU架構,完成某項操作的實現方式可能不同,因此在編譯操作系統的時候不應該出現交叉編譯的情況(比如在AMD上編譯在Intel上運行)。
也就是說,想要在某個平臺上使用操作系統,需要針對這個平臺進行編譯。這無疑增加了學習和使用的難度,作為初學者而言,這是噩夢。於是出現了一些組織,他們來對Linux的源碼和外圍的一些軟體進行編譯集成,然後發行出來,這就是Linux的發行版。這樣的公司或組織有RedHat,Debian等
13.軟體包管理器
早期的軟體都是隨著內核一起打包發佈的,這樣有個明顯的缺點:不利於軟體的管理,如軟體的安裝,卸載等。於是出現了軟體包管理器,用來方便軟體的管理,安裝,卸載等。比較著名的有dpt(debian),rpm(redhat)等。
14.Linux的基本原則
- 組裝:組合功能目的單一的小程式,完成複雜的任務
- 一切皆文件
- 儘量避免捕獲用戶介面(交互),比如輸入ls,馬上列出目錄下的文件,不需要其他操作。
- 配置文件保存為純文本格式——一個簡單的文本編輯器就可以完成所有的功能。
15.命令的構成
基本格式為:命令 = 命題主體 + 選項 + 參數。
命令執行:輸入命令後,由shell將指令發送給kernel,kernel即對該指令進行判斷,決定是否執行。
命令可以跟上選項,用來修正命令的執行方式。格式為:
- 短選項:-單一字元,如 -a,-l,-h
- 長選項:--單詞,如 --help
短選項多個選項可以組合:-a -h 可以組合成 -ah。長選項通常不能組合。
命令的參數:命令的表示命令的作用對象。如:ls -ah /etc 為列出 /etc 目錄下的文件,如果不加參數,預設為當前目錄。
16.一些瑣碎知識
Linux(我這裡使用的是RedHat)下一般有6個終端可以使用,可以按鍵盤組合鍵 ctrl + alt + f1~f6切換。
$ startx & -> 啟用圖形界面。
Linux圖形界面的類型:Gnome(C),KDE(C++),XFace(輕量級圖形界面)。
Linux命令行界面類型:bash csh zsh ksh....
任何跟shell相關的啟動的程式,只要shell關了,這個程式也就關了(這不廢話嗎)。
su:切換用戶(switch user 縮寫)。
su root [-l] :半切換,完全切換。
passwd:修改密碼,連輸兩次即可。
對於root,可以隨便修改,對於普通用戶,需要滿足密碼複雜性規則。
17.總結
這篇文章主要介紹了CPU和操作系統的簡單工作原理,涉及到的概念有:運算器,控制器,寄存器,匯流排,南北橋,操作系統,shell等。算是對基礎知識的一些總結,由於沒有深刻學習,文章中有很多漏洞,更有許多模糊的知識沒有加以說明。文章組織不夠嚴謹,只是單純的將知識點分條羅列,邏輯性有待加強。
就以這篇文章開始,一步步打開Linux的大門吧。