標(biāo)題: 漫談計算機硬件體系對編程的影響和意義 [打印本頁]
作者: 芯片去字筆 時間: 2019-9-16 22:27
標(biāo)題: 漫談計算機硬件體系對編程的影響和意義
今天由于時間不多,難有旁征博引的長文來跟大家解釋清楚計算機、存儲,及其對編程的影響。不過,有一點自己微小的見解與大家分享。雖然微小,但確實給自己減輕了很多在技術(shù)方面的理解成本和成長負擔(dān)。個人覺得也應(yīng)是有些分享價值的。
1. 計算機組成現(xiàn)代電子計算機從二十世紀四十年代末發(fā)展至今,以EDVAC計算機為標(biāo)志,到目前為止67年間計算機硬件體系的核心都未曾發(fā)生過變化,都是馮諾依曼體系的。注意這里說的是EDVAC而非第一臺通用計算機ENIAC。EDVAC于1949年交付,1951年正式運行,1961年完成使命退出歷史舞臺。
1.1 題外話:編程語言與軟件系統(tǒng)的發(fā)展和自舉本小節(jié)的目的是為了解決大家常有的疑惑:現(xiàn)代編程語言和軟件都是逐步迭代的方式演進,那最早最早的編程語言和操作系統(tǒng)是怎么來的? 越是追溯事物的起源,越是能發(fā)現(xiàn)其本質(zhì)。
先提及一下EDVAC服役的這幾年(1949-1961)間出現(xiàn)過的,至今影響深遠的編程語言。在這12年間,與硬件平臺強相關(guān)的特定匯編于1949年最早出現(xiàn),1951年各種匯編方言開始興起。Fortran于1954年開始開發(fā),1957年正式由IBM發(fā)布。約翰·麥卡錫于1958年基于IPL語言發(fā)明了Lisp函數(shù)式編程語言,主要用于人工智能。同年, ALGOL也誕生了。1959年COBOL也問世。Fortran、Lisp、ALGOL,就是后來幾乎所有高級編程語言的鼻祖,它們至今自己也發(fā)揮著巨大的作用。
最早的都是用機器語言通過穿孔卡片的形式搞出來的,像Fortran早期都是穿孔卡片進行編程。后來的新語言和新系統(tǒng),都是基于前輩們自舉而來。有了編程語言之后,程序,包括操作系統(tǒng)程序是如何誕生出來的就可想而知。
編程語言和軟件自舉的過程。純手工用穿孔紙的形式用機器語言編寫了早期的具有特定功能的程序,比如存粹為了計算導(dǎo)彈等軍事用途的程序。后來為了編程方便,各類匯編方言誕生,所以同樣純手工機器碼編程寫個匯編翻譯器,能把匯編源碼翻譯成機器語言,故而就能用匯編語言來寫各種各樣的特定功能的程序了。因為匯編語言翻譯之后得到的最終程序是機器可直接執(zhí)行的機器碼,所以用匯編1.0寫個匯編2.0翻譯器也沒問題的,匯編2.0成熟后,就能完全拋棄匯編匯編1.0了。同樣的,直接用機器碼或者匯編語言,寫個A語言的編譯器也沒問題,A語言編譯器穩(wěn)定之后,也可以用A語言來寫A語言自己的編譯器,用匯編寫的A語言編譯器就可以拋棄了。
如雷貫耳的C語言,就是按上述過程基于CPL和BCPL語言發(fā)展而來的,后來很多語言用C寫第一版編譯器也不足為奇了,比如Python官方實現(xiàn)就一直用的是C,而Pypy是用Python自舉的。
1.2 馮諾依曼體系精要首先要明確一點,馮諾依曼體系因其設(shè)計EDVAC時而系統(tǒng)提出來的,但是其中的核心思想和觀念,絕不是馮諾依曼一人靈光乍現(xiàn)的個人杰作。有很多前輩們的努力,馮諾依曼是那個有機會總結(jié)并在大型項目中實踐的幸運兒。
1.2.1 兩個核心原則:- 計算機程序和待處理的數(shù)據(jù)無差別存儲在存儲器中
這里隱含了兩點,運行時存在哪里?掉電后存在哪里?也就是主存和外存,馮諾依曼的報告中是有專門提及主存和外存的。更進一步說,程序亦是數(shù)據(jù)的一種。 - 使用二進制,而非十進制
ENIAC使用的就是十進制。
1.2.2 五個組成部分- 運算器、控制器
- 存儲器
- 輸入設(shè)備、輸出設(shè)備
1.2.3 更簡化地理解在本人理解來看,計算機拋開外圍設(shè)備后,最核心的東西就是運算器和存儲器。 簡言之,運算與存儲?刂破魇强梢詥为毩谐鰜淼模怯捎诳刂破鞅举|(zhì)就是根據(jù)不同的判定條件選擇不同的處理過程,和一般的運算沒有根本上的區(qū)別,我把它粗略地歸為運算類。這樣歸納也是有理由的,因為在早期的機電計算機中,有運算器和存儲器就完全可以工作了(后來有了晶體管的計算機稱為電子計算機)。
這樣的簡化的作用是為了減輕對計算機體系的理解成本,如何個減輕法,請繼續(xù)看后文。
1.3 計算機組成總結(jié)關(guān)鍵字:程序亦數(shù)據(jù)、二進制、運算器、存儲器。
其中進制不必多談,以后會發(fā)文專門談?wù)劄楹畏且嵌M制在這種體系結(jié)構(gòu)下最恰當(dāng),可不僅僅是高電平、低電平那么表面的解釋。程序亦是數(shù)據(jù),這原本是指馮諾依曼體系中程序和數(shù)據(jù)無差別對待,一起存放在存儲器里就行。但我們可以從這條延伸出很多編程上的思想,程序就是指令集,指令等同于數(shù)據(jù)對待時,問題就會簡化很多,也會靈活很多。
函數(shù)式編程語言說函數(shù)是一等公民,而一個函數(shù)本就是一段程序,當(dāng)有了“程序亦數(shù)據(jù)”的思想后,拿函數(shù)作為入?yún)鱽韨魅ゲ皇呛茏匀坏厥聠幔坎恢喇?dāng)初Lisp的誕生,有沒有受到這一點的啟發(fā),也許Lisp純粹是按數(shù)學(xué)上對待函數(shù)的態(tài)度來的。不過應(yīng)了我常說那句話:世界是圓的。
同理,面向?qū)ο缶幊痰恼Z言中,一個對象本就是一組數(shù)據(jù)和其操作的封裝,把對象當(dāng)做參數(shù)傳來傳去也在情理之中。命令式語言把命令當(dāng)做數(shù)據(jù)操作,這本就是它們的工作方式,由計算機硬件組成結(jié)構(gòu)而來的工作方式。
2. 存儲曾經(jīng)在”細學(xué)Python”QQ群里問群友,大家覺得存儲的本質(zhì)是為了什么?回答五花八門,有的說是為了賺錢讓公司不倒閉,那為什么、憑什么能賺錢了?有的說是為了再利用,再利用來干什么?有的說是為了備份。有的說是為了能給程序處理,各種各種。這些回答都是有道理的,但是從一種“事物原本”的角度來講,不是很到位。
不論是外存、內(nèi)存、數(shù)據(jù)庫軟件、瀏覽器端的Cookie、服務(wù)端的Session、磁盤上的文件等等,乃至是超越計算機體系之外,人腦中的記憶,各種各樣,五花八門的存儲形式,都有一個共同點:為了狀態(tài)的延續(xù)。不論是從運行原理上、業(yè)務(wù)邏輯上、商業(yè)目的上等各種層次各種維度來觀察,這個結(jié)論都能得到解釋。
瀏覽器端的Cookie和服務(wù)端的Session不必多說,為了使用戶的登錄狀態(tài)得以延續(xù);程序運行時在內(nèi)存中的數(shù)據(jù)存儲是為了程序的運行時狀態(tài)得以延續(xù);電腦關(guān)機以后要將數(shù)據(jù)數(shù)據(jù)回寫磁盤,是為了下次開機后能夠延續(xù)上一次關(guān)機前的開機狀態(tài);數(shù)據(jù)庫中存儲的數(shù)據(jù),是為了讓業(yè)務(wù)系統(tǒng)的運行時狀態(tài)、業(yè)務(wù)邏輯狀態(tài)不斷延續(xù);人腦能夠根據(jù)存儲的記憶觸景生情,是為了在若干時間后延續(xù)之前的那種情緒狀態(tài),比如運動員若干年后看著自己曾經(jīng)拿到的金牌能夠置身于當(dāng)初得獎的喜悅感受中。還有很多例子拿來解釋。
3. 硬件體系和存儲的本對編程的意義在上一篇《編程到底是個什么玩意》中已經(jīng)說了一條很重要的原則:事物是分層次的,軟件也是。層次思維明晰的話,就容易思考清楚很多軟件中的架構(gòu)和設(shè)計。
3.1 運算器與存儲器對編程的意義編程語言各種各樣,之前我們已經(jīng)談過了程序的共同本質(zhì),那么硬件體系對編程有什么影響呢?首先是硬件的可能性直接決定了軟件的可能性。其次,既然硬件體系可歸納為兩大類:運算器與存儲器。那么軟件體系也逃不脫這兩大類,做運算的與做存儲的。
運算與存儲,就好比是兩個基本元素,它們在硬件體系中存在,也在軟件體系中存在。它們還能夠按層次組織,大層次的元素可以囊括小層次的元素。舉個例子:MySQL數(shù)據(jù)庫從宏觀看是一個存儲程序,而要讓MySQL這個級別的程序正確工作,只有一個層次是不可能的,它必須包含運算類的模塊(按上文所述,控制類的也屬于此),也包含了存儲類的模塊,還有各種不同的層次逐級分下來,最終落實到MySQL的每一行源代碼,哪函數(shù)是是它所在的那個級別的存儲作用的,哪個函數(shù)是該級別的運算作用的;某個函數(shù)中,哪一行數(shù)和存取數(shù)據(jù)相關(guān)的,哪一行是與運算數(shù)據(jù)相關(guān)的……最終,指令而且還會落實到硬件上的運算器與存儲器上。
由于存儲到底還是存儲的是數(shù)據(jù),故而明白了存儲的地位以后,就知道了計算機程序所操作的存儲器與存儲器中的數(shù)據(jù)的重要性。程序要操作的存儲器是內(nèi)存,而數(shù)據(jù)在編程語言中的表現(xiàn)形式就是該語言支持的各種數(shù)據(jù)結(jié)構(gòu),包括基本數(shù)據(jù)結(jié)構(gòu)和擴展數(shù)據(jù)結(jié)構(gòu),基本數(shù)據(jù)結(jié)構(gòu)是就是整數(shù)、浮點數(shù)等,擴展數(shù)據(jù)結(jié)構(gòu)包括結(jié)構(gòu)體、對象等等。故而學(xué)習(xí)一門編程新語言,你首要關(guān)注的是如何進行內(nèi)存的分配與使用,以及數(shù)據(jù)結(jié)構(gòu)的操作。
還有一個很明確的編程指導(dǎo)思路:從程序功能講,你所要完成的項目應(yīng)該歸為運算類還是存儲類?當(dāng)要做模塊拆分時,這兩種分類又能指導(dǎo)你進行模塊劃分。為了更清晰,你可以按運算器、控制器、存儲器三種來分。再往下可以指導(dǎo)你的類、函數(shù)的劃分,再往下就能指導(dǎo)代碼的編寫,哪一行該操作哪個數(shù)據(jù)對象,它存在于哪里?要經(jīng)過怎么樣的運算,要到哪里去?……
當(dāng)軟件需要優(yōu)化時,有兩個大方向可以考慮,是運算需要優(yōu)化,還是存儲需要優(yōu)化?假如當(dāng)運算需要優(yōu)化時,哪個級別負責(zé)運算的程序需要優(yōu)化?要優(yōu)化這個級別的運算,那其子級別中的運算和存儲兩大類程序又是哪類更應(yīng)該優(yōu)化?當(dāng)程序功能不足需要添加功能時,要添加充當(dāng)運算角色的功能呢?還是要添加充當(dāng)控制角色的?抑或是要充當(dāng)存儲功能的?……
有的同學(xué)可能會想,像WEB界面的內(nèi)容,應(yīng)該歸為哪類?宏觀看,WEB界面只是服務(wù)端輸出的結(jié)果,通過網(wǎng)絡(luò)I/O這種方式暫時存放到了客戶端,瀏覽器把這些數(shù)據(jù)處理渲染給了終端用戶。網(wǎng)絡(luò)I/O屬于我理解的計算機外圍設(shè)備,當(dāng)然,非要劃分個歸類,那應(yīng)當(dāng)歸為存儲類。
總而言之,運算與存儲這兩個基本元素,構(gòu)建起了馮諾依曼體系下計算機軟硬件的高樓大廈。
3.2 狀態(tài)延續(xù)性對編程的意義無需多言,將會指導(dǎo)我們定義程序中的數(shù)據(jù)種類、數(shù)據(jù)結(jié)構(gòu),優(yōu)化數(shù)據(jù)的的核心指南。你希望程序這一刻是個什么狀態(tài)?經(jīng)過運算后,下一刻又是一個什么狀態(tài)?要不要延續(xù)?那些基本數(shù)據(jù)齊活了以后才能使這個狀態(tài)得以延續(xù)?如果1個字節(jié)的數(shù)據(jù)就能讓狀態(tài)延續(xù)下去,用1KB數(shù)據(jù)來解決問題是不是有些浪費?
在有些程序里,磁盤IO速度不足,滿足不了CPU的處理速度,那怎么辦?那是CPU里的計算狀態(tài)延續(xù)不下去了,出現(xiàn)等待磁盤IO的斷檔,很明顯的優(yōu)化思路就是增加一種程序來解決這個事情。增加運算類的程序能解決這個問題嗎?看樣子不太行,應(yīng)為CPU作為運算器的存在它已經(jīng)有強大優(yōu)勢了。那就加存儲類程序唄,用內(nèi)存來做存儲嘛,好像問題可以得解了。
如果隨著程序發(fā)展,又滿足不了了怎么辦?換性能更好的存儲器,一種存儲器解決不了的問題就兩種存儲器解決,兩種存儲器解決不了的就三種來解決…… 君不見,這就是馮諾依曼體系下的硬件發(fā)展與軟件優(yōu)化趨勢,硬件中的多級緩存,從CPU到內(nèi)存到磁盤,軟件中的多級緩存從應(yīng)用程序到數(shù)據(jù)庫程序到操作系統(tǒng)程序,無處不在……
以后再發(fā)文說說多級緩存的事。
另外,存儲是為了狀態(tài)延續(xù)這條指導(dǎo)規(guī)則,還可以發(fā)揮更多的作用,比如在數(shù)據(jù)災(zāi)難恢復(fù)、程序不間斷服務(wù)而切換存儲介質(zhì)或者切換數(shù)據(jù)庫上。大家可以發(fā)揮一下,不再多寫。
4. 總結(jié)本文也許有些同學(xué)看起來就是“假大空”,原因之一是確實篇幅有限,不能再多啰嗦;其二是偏理論經(jīng)驗性的闡述,而缺少實例;其三是這部分同學(xué)可能編程經(jīng)驗還不足。
作者: yuche2018 時間: 2019-9-17 10:21
分析的有道理 學(xué)習(xí)了
歡迎光臨 (http://www.torrancerestoration.com/bbs/) |
Powered by Discuz! X3.1 |