碼農需要知道的“潛規則”
碼農需要知道的“潛規則”
轉自:碼農翻身
0 前言
吳思先生在《潛規則》(中國歷史中的真實遊戲)一書中講述了很多生動、有趣的官場故事,透過歷史表象,揭示出隱藏在正式規則之下、實際上支配著社會運行的不成文的規矩, 非常值得閱讀。
這篇文章準確來講並不是計算機/軟件開發的潛規則, 實際上是那些你可能在使用,卻沒有註意到的一些原理和規律,這些東西很重要,掌握了能夠指導你以後的開發和設計。
1 上帝的規矩:局部性原理
局部性原理這個原理講的是在一段時間裏, 整個程序的執行僅限於程序的某一個部分, 相應的, 程序訪問的存儲空間也局限於某一個內存區域, 具體分為:
- (1) 時間局部性:是指如果程序中的某條指令一旦執行,則不久之後該指令可能再次被執行; 如果某數據被訪問,則不久之後該數據可能再次被訪問。
- (2) 空間局部性: 是指一旦程序訪問了某個存儲單元,則不久之後。其附近的存儲單元也將被訪問。
為什麽是這樣? 我也不知道, 可能是計算機界的上帝定下的規矩。
但是這個原理的用處可就大了, 例如Java 虛擬機, 本來是解釋執行.class 文件,性能不怎麽樣, 但是利用局部性原理, 就可以找到那些常用的, 所謂的熱點(Hotspot)代碼, 然後把他們編譯成本地原生代碼(native code), 這樣執行效率就和C/C++差不多了。
當然這個原理更大的用處就是下面要提到的緩存。
2 坐飛機的怎麽和坐驢車的打交道: 緩存
為什麽需要緩存(Cache)?
本質的原因是速度的不匹配。 CPU比內存快100多倍, 比硬盤快1000多萬倍。
如果CPU每次做事的時候, 都等著內存和硬盤, 那整個計算機的速度估計要慢的要死了。
所以根據局部性原理, 操作系統會把經常需要用的數據從硬盤取到內存,CPU 會把經常用的數據從內存取到自己的緩存中。通過這種辦法等待的問題能帶到極大的緩解。
在Web 開發中,緩存更是非常常見的, 由於數據庫(硬盤)太慢, 大部分Web系統都會把最常用的業務數據放到內存中緩存起來。
3 拋棄細節: 抽象
抽象是計算機科學中最為重要的概念之一
當我們遇到復雜問題的時候, 抽象是非常重要的武器。
《深入理解計算機系統》一書中提到:
指令集是對CPU的抽象, 文件是對輸入/輸出設備的抽象, 虛擬存儲器是對程序存儲的抽象, 進程是對一個正在運行的程序的抽象, 而虛擬機是對整個計算機(包括操作系統、處理器和程序)的抽象。
- CPU集成電路硬件無比復雜, 但是我們寫程序肯定不用接觸這些硬件細節, 那樣就累死了, 我們只要遵循CPU的指令集, 程序就可以正確的運行, 而不用關心指令在硬件層次到底是怎麽運行的。
- 硬盤也是這樣, 有磁道,柱面,扇區, 我們寫應用層程序也不用和這些煩人的細節打交道, 在操作系統和設備驅動的配合下, 我們只需要面對一個個“文件”,打開,讀取,關閉就行了。 操作系統會把邏輯的文件翻譯成物理磁盤上的字節。
- 再比如為了實現數據的共享,數據的一致性和安全性,需要大量的,復雜的程序代碼來實現, 每個應用程序都實現一份肯定不是現實的。 所以計算機科學抽象出了一個叫數據庫的東西, 你只需要安裝數據庫軟件, 使用SQL和事務就能實現多用戶對數據的安全訪問了。
參見文章《抽象, 程序員必備的能力》
4 我只想和鄰居打交道: 分層
分層其實也是抽象的一種,它通過層次把復雜的,可能變化的東西隔離開來, 某一層只能訪問它的直接上層和下層, 不能跨層訪問。
圖1 例如網絡協議分層
圖2 Web開發的分層
分層的好處就是隔離變化, 在接口不變的情況下, 某一層的變化只會局限於本層次內。 即使是接口變化, 也僅僅會影響調用方。
5 我怕等不及: 異步調用
當你的程序需要等待一個長時間的操作而被阻塞住時而無所事事的時候, 異步調用就派上用場了。
異步調用簡單就是說: 我等不及你了, 先去做別的事情, 你做完了告訴我一聲。
回到最早的那個CPU的例子, CPU速度太快, 當它想讀取硬盤文件的時候,是不會等待慢1000多萬倍的硬盤的, 它會啟動一個DMA , 不用通過CPU, 直接把數據從硬盤讀到內存, 讀完以後通過中斷的方式來通知CPU。
Node.js 和 Web服務器Nginx 也是這樣, 一個線程或若幹個線程處理所有的請求, 遇到耗時的操作, 絕不等待, 馬上去幹別的事情,等到耗時操作完成後,再來通知這些幹活的線程。
還有著名的AJAX , 當瀏覽器中的javascript發出一個Http 請求的時候, 也不會等待從服務器端返回數據, 只是設置一個回調函數, 服務器響應數據回來的時候調用一下就行了。
6 大事化小, 小事花了 : 分而治之
分而治之的基本思想是將一個規模比較大的問題分解為多個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,最後組合起來就可得到原問題的解。
由於子問題和原問題性質相同, 所以很多時候可以用遞歸。
歸並排序就是一個經典的例子, 數據結構與算法書上到處都是, 這裏就不在贅述了。
如果把分而治之泛化一下, 到軟件設計領域, 就可以認為是把一個大問題逐步分解的過程
碼農需要知道的“潛規則”