【非科班前端】注意了! 計算機組成原理知識已送到你嘴邊!

前端開發人員中,有至關大比例的同窗不是科班出來的,因此對於基本的科班必修課,例如:計算機組成原理操做系統計算機網絡數據結構和算法等知識接觸很少。前端

當你越深刻學習,越會發現這些知識的重要性。算法

好比你們都知道js裏面0.1 + 0.2不等於0.3的,爲何呢?這就牽扯到計算機組成原理中浮點數的表示方法,以及浮點數的加減運算(正文會有白話版解答)。編程

又例如從鍵盤輸入a+b這個指令,如何經過cpu的調度輸出到屏幕上呢?這就涉及到馮諾依曼體系,若是你是編程人員,都不清楚數據從鍵盤到屏幕的基本流向,恐怕很難說本身是合格的編程人員吧。數組

本文是一個計算機組成原理最基本的入門文章,我以爲前端沒有必要那麼深刻這個專題,具有基本的計算機組成原理的常識便可。緩存

一、計算機的工做原理

首先,計算機最基本的5大組成部分以下圖,分別爲:輸入設備(好比鍵盤), 存儲器(好比內存), 運算器(cpu), 控制器(cpu), 輸出設備(顯示器)。bash

工做原理以下網絡

1.1 控制器 ---> 控制輸入設備 ----> 指令流向內存

當咱們輸入數據的時候,cpu裏的控制器會讓輸入設備把這些指令存儲到存儲器(內存)上。數據結構

1.2 控制器分析指令 ---> 控制存儲器 ---> 把數據送到運算器

控制器分析指令以後, 此時讓存儲器把數據發送到運算器裏(控制器運算器都在cpu裏面)數據結構和算法

這裏須要注意,存儲器既能存儲數據,還能存儲指令(後面會講指令是什麼,怎麼執行) 編程語言

1.3 控制器控制運算器作數據的運算 而且將運算結果返回存儲器

1.4 控制器控制存儲器將結果返回給輸出設備

從接下來,咱們更近一步,看看計算機內部,CPU是怎麼跟存儲器交互的。

二、CPU及其工做過程

CPU中比較重要的兩個部件是運算器控制器,咱們先來看看運算器的主要做用

2.1 運算器主要部件

如上圖,運算器裏最重要的部件是ALU,中文叫算術邏輯單元,用來進行算術邏輯運算的。其它的MQ,ACC這些咱們不用管了,是一些寄存器

2.2 控制器主要部件

控制器中最重要的部件是CU(控制單元),只要是分析指令,給出控制信號

IR(指令寄存器),存放當前須要執行的指令

PC存放的指令的地址。

2.3 舉例 - 取數指令執行過程

首先,是取指令的過程以下

  • 第一步,PC,也就是存放指令地址的地方,咱們要知道下一條指令是什麼,就必須去存儲器拿,CPU才知道接下來作什麼。PC去了存儲器的MAR拿要執行的指令地址,MAR(存儲器裏專門存指令地址的地方)
  • 第二步和第三步,MAR去存儲體內拿到指令以後,將指令地址放入MDR(存儲器裏專門存數據的地方)
  • 第四步MDR裏的數據返回到IR裏面,IR是存放指令的地方,咱們把剛纔從存儲體裏拿的指令放在這裏

而後,分析指令,執行指令的過程以下

  • 第五步, IR將指令放入CU中,來分析指令,好比說分析出是一個取數指令,接着就要執行指令了(這裏取數指令,其實就是一個地址碼,按着這個地址去存儲體取數據)
  • 第六步,第七步 IR就會接着去找存儲體裏的MAR(存儲地址的地方),MAR就根據取數指令裏的地址嗎去存儲體裏去數據
  • 第八步,取出的數據返回給MDR(存放數據的地方)
  • 第九步,MDR裏的數據放到運算器的寄存器裏,這裏的取指令的過程結束了。

來個插曲,咱們知道數據在內存裏是二進制存着,也就是0和1, 0和1怎麼用表示呢?

咱們拿其中一種存儲0和1的方式來講明

  • 電容是否有電荷,有電荷表明1,無電荷表明0
  • 以下圖

三、計算機編程語言

咱們看看機器語言,怎麼表示存放一個數的指令,例以下圖

咱們來看二進制代碼 0000,0000,000000010000

  • 其中第一個0000,表示的是彙編語言裏的LOAD,也就是加載,加載什麼呢
  • 加載地址000000010000上的數據到第二個0000(寄存器的位置)。

接下來,咱們看看若是是彙編語言怎麼表示

LOAD A, 16意思是將存儲體內的16號單元數據,放到寄存器地址A中 ADD C, A, B意思是將寄存器裏的A,B數據相加,獲得C STORE C, 17意思是將寄存器裏的數據存到存儲體17號單元內

最後,咱們看看怎麼用高級語言表示

高級語言是否是很簡單,就一個a+b,你都不用去考慮寄存器存儲體這些事。

這部分的總結

高級語言通常有兩種方式轉換爲機器語言

  • 一種是直接藉助編譯器,將高級語言轉換爲二進制代碼,好比c,這樣c運行起來就特別快,由於編譯後是機器語言,直接就能在系統上跑,但問題是,編譯的速度可能會比較慢。
  • 一種是解釋性的,好比 js,是將代碼翻譯一行成機器語言(中間可能會先翻譯爲彙編代碼或者字節碼),解釋一行,執行一行

須要注意的是,按照第一種將大量的高級代碼翻譯爲機器語言,這其中就有很大的空間給編譯器作代碼優化,解釋性語言就很難作這種優化,可是在v8引擎中,js仍是要被優化的,在編譯階段(代碼分編譯執行兩個階段)會對代碼作一些優化,編譯後當即執行的方式一般被稱爲 JIT (Just In Time) Comipler

四、進制轉換

接下來4.3這個小節會解釋爲何0.1 + 0.2 等於0.3

4.1 二進制如何轉化爲十進制

例如2進制101.1如何轉化爲10進制。(有些同窗以爲能夠用parseInt('101.1', 2),這個是不行的,由於parseInt返回整數)

轉化方法以下:

上圖的規則是什麼呢?

二進制的每一個數去乘以2的相應次方,注意小數點後是乘以它的負相應次方。 再舉一個例子你就明白了,

二進制1101轉爲十進制

4.2 十進制整數轉爲二進制

JS裏面能夠用toString(2)這個方法來轉換。若是要用通用的方法,例如:將十進制數(29)轉換成二進制數, 算法以下:

  • 把給定的十進制數29除以2,商爲14,所得的餘數1是二進制數的最低位的數碼
  • 再將14除以2,商爲7,餘數爲0
  • 再將7除以2,商爲3,餘數爲1,再將3除以2,商爲1,餘數爲1
  • 再將1除以2,商爲0,餘數爲1是二進制數的最高位的數碼

其結果爲:11101

4.3 十進制小數轉爲二進制

方式是採用「乘2取整,順序排列」法。具體作法是:

  • 用2乘十進制小數,能夠獲得積,將積的整數部分取出-
  • 再用2乘餘下的小數部分,又獲得一個積,再將積的整數部分取出-
  • 如此進行,直到積中的小數部分爲零,或者達到所要求的精度爲止

咱們具體舉一個例子

如: 十進制 0.25 轉爲二進制

  • 0.25 * 2 = 0.5 取出整數部分:0

  • 0.5 * 2 = 1.0 取出整數部分1

即十進制0.25的二進制爲 0.01 ( 第一次所獲得爲最高位,最後一次獲得爲最低位)

此時咱們能夠試試十進制0.10.2如何轉爲二進制

0.1(十進制) = 0.0001100110011001(二進制)
十進制數0.1轉二進制計算過程:
0.1*2=0.2……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.2」接着計算。
0.2*2=0.4……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.4」接着計算。
0.4*2=0.8……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.8」接着計算。
0.8*2=1.6……1——整數部分爲「1」。整數部分「1」清零後爲「0」,用「0.6」接着計算。
0.6*2=1.2……1——整數部分爲「1」。整數部分「1」清零後爲「0」,用「0.2」接着計算。
0.2*2=0.4……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.4」接着計算。
0.4*2=0.8……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.8」接着計算。
0.8*2=1.6……1——整數部分爲「1」。整數部分「1」清零後爲「0」,用「0.6」接着計算。
0.6*2=1.2……1——整數部分爲「1」。整數部分「1」清零後爲「0」,用「0.2」接着計算。
0.2*2=0.4……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.4」接着計算。
0.4*2=0.8……0——整數部分爲「0」。整數部分「0」清零後爲「0」,用「0.2」接着計算。
0.8*2=1.6……1——整數部分爲「1」。整數部分「1」清零後爲「0」,用「0.2」接着計算。
……
……
因此,獲得的整數依次是:「0」,「0」,「0」,「1」,「1」,「0」,「0」,「1」,「1」,「0」,「0」,「1」……。
由此,你們確定能看出來,整數部分出現了無限循環。
複製代碼

接下來看0.2

0.2化二進制是
0.2*2=0.4,整數位爲0
0.4*2=0.8,整數位爲0
0.8*2=1.6,整數位爲1,去掉整數位得0.6
0.6*2=1.2,整數位爲1,去掉整數位得0.2
0.2*2=0.4,整數位爲0
0.4*2=0.8.整數位爲0
就這樣推下去!小數*2整,一直下去就行
這個數整不斷
0.0011001
複製代碼

因此0.10.2都沒法完美轉化位二進制,因此它們相加固然不是0.3

五、定點數和浮點數

首先,什麼是定點數呢?

5.1 定點數

如上圖,舉例純整數的二進制1011-1011,若是是整數,符號位用0表示,若是是負數符號爲用1表示

同理,純小數表示舉例以下:

那若是不是純小數或者純整數,該怎麼表示呢?

好比10.1, 能夠乘以一個比例因子,將10.1 ---> 101 比例因子是10, 或者10.1 ---> 0.101比例因子是100

定點數很簡單,接下來咱們介紹浮點數,再JS裏面,數字都是用雙精度的浮點數,因此學習浮點數對咱們理解JS的數字有幫助。

5.2 浮點數

浮點數怎麼表示呢?

上面是十進制的科學計數法,從中咱們須要瞭解幾個概念,一個是尾數基數階碼

  • 尾數必須是純小數,因此上圖中1.2345不知足尾數的格式,須要改爲0.12345
  • 基數,在二進制裏面是2
  • 階碼就是多少次方

因此浮點數通用表示格式以下:

  • S表明尾數
  • r表明基數
  • j表明階碼

這裏須要注意的是,浮點數的加減運算,並非像咱們上面介紹的那樣簡單,會通過如下幾個步驟完成

這些名詞你們感興趣的話,能夠去網上查詢,咱們只要瞭解到浮點數加減運算很麻煩就好了,但若是你要作一個浮點數運算的庫,你確定是要徹底掌握的。

六、局部性原理和catche(緩存)

先看下圖

(說明一下,MDRMAR雖然邏輯上屬於主存,可是在電路實現的時候,MDRMARCPU比較近)

上圖是在執行一串代碼,能夠理解位js的for循環

const n = 1000;
const a = [1, 2, 3, 4, 5, 6, 7]
for(let i =0; i < n; i++) {
    a[i] = a[i] + 2
}
複製代碼

咱們能夠發現

  • 數組的數據有時候在內存是連續存儲的
  • 若是咱們要取數據,好比從內存取出a[0]的數據須要1000ns(ns是納秒的意思),那麼取出a[0]到a[7]就須要1000 * 8 = 8000 ns
  • 若是咱們cpu發現這是取數組數據,那麼我就把就近的數據塊a[0]到a[7]所有存到緩存上多好,這樣只須要取一次數據,消耗1000ns

cahce就是局部性原理的一個應用

  • 空間局部性:在最近的將來要用到的信息(指令數據),極可能與如今正在使用的信息在存儲空間上是鄰近的
  • 時間局部性:在最近的將來要用到的信息,極可能是如今正在使用的信息

能夠看到cache一次性取了a[0]a[9]存儲體上的數據,只須要1000ns,由於Cache高速存儲器,跟cpu交互速度就比cpu主存交互速度快不少。

接下里,進入最後一節(略過對總線知識的學習),I/O設備的演變

七、I/O設備的演變

I/O是什麼呢?

輸入/輸出(Input /Output ,簡稱I/O),指的是一切操做、程序或設備與計算機之間發生的數據傳輸過程。
複製代碼

好比文件讀寫操做,就是典型的I/O操做。接下來咱們看一下I/O設備的演進過程

在早期的計算機裏, cpu如何知道 I/O設備已經完成任務呢?好比說怎麼知道 I/O設備已經讀取完一個文件的數據呢? CPU會不斷查詢 I/O設備是否已經準備好。這時, cpu就處於等待狀態。也就是 cpu工做的時候, I/O系統是不工做的, I/O系統工做, cpu是不工做。

接着看第二階段

  • 爲了解決第一階段CPU要等待I/O設備串行的工做方式,全部I/O設備經過I/O總線來跟CPU打交道,一旦某個I/O設備完成任務,就會以中斷請求的方式,經過I/O總線,告訴CPU,我已經準備好了。

  • 可是對於高速外設,它們完成任務的速度很快,因此會頻繁中斷CPU, 爲了解決這個問題,高速外設跟主存之間用一條直接數據通路,DMA總線鏈接,CPU只須要安排開始高速外設作什麼,剩下的就不用管了,這樣就能夠防止頻繁中斷CPU

最後來看一下第三階段

第三階段,CPU經過通道控制部件來管理I/O設備,CPU不須要幫它安排任務,只須要簡單的發出啓動和中止相似的命令,通道部件就會自動的安排相應的I/O設備工做

本文完結,但願你們點個贊,比心💗。

相關文章
相關標籤/搜索