作者簡介 原創(chuàng)微信公眾號郭霖 WeChat ID: guolin_blog
大家早上好式散,新的一周開始了!
本篇是江湖人稱小白哥的第二篇投稿惧眠,分享了他從Unix/Linux中獲得的編程感悟籽懦,希望能夠幫助到大家。
江湖人稱小白哥的博客地址:
http://blog.csdn.net/dd864140130
前言
寫本文的最初靈感源于16年11月份我將工作環(huán)境切換到Mac OS上,其中一些使用”差異”讓我開始對 Unix/Linux?中設計產(chǎn)生了濃厚的興趣.雖然從13年開始使用redhat,再到后來一直使用的 ubuntu,但卻從來關注過這些,特此記錄.
在整個探究過程中,那些經(jīng)典的著作再次讓我獲益匪淺:C和指針,C專家編程,深入理解計算機系統(tǒng)(原書第3版),Linux/Unix設計思想,Linux Shell腳本攻略.前兩本書購于13年,斷斷續(xù)續(xù)的讀了許久,這一次重讀令人豁然開朗,其中許多不解之處在深入理解計算機系統(tǒng)一書得到答案,而后兩本則是年前有幸讀到.其中 Linux/Unix 設計思想不談技術細節(jié),卻揭示了 Linux/Unix 隱含的指導思想,最后一本則是從 Shell 出發(fā),以實踐的角度教你如何利用 Shell(Bash) 在 Linux/Unix 平臺上構(gòu)建有效的解決方案,實乃入門進階必備啊.
從女媧造人說起
俗說天地開辟,未有人民,女媧摶黃土作人.劇務,力不暇供,乃引繩于泥中,舉以為人.故富貴者,黃土人氛魁;貧賤人,引繩人也…
神一樣的程序員
“女媧造人”可謂人人皆知,女媧是神,而程序員是能力上最接近女媧的存在.如果說女媧創(chuàng)造的是真實的世界,那么程序員是創(chuàng)造數(shù)字的世界,我們所寫下的每行代碼,所構(gòu)建每個程序,都在讓這個數(shù)字世界變得豐富多彩.
沒有哪個職業(yè)可以像程序員:賦予代碼以生命,創(chuàng)造數(shù)字世界中的花花草草!盡管我們擁有近乎神的能力,本身卻也受著NIH綜合征的困擾.
程序員之殤
NIH綜合征是什么?
Not invented here (NIH) is a stance adopted by social, corporate, or institutional cultures that avoid using or buying already existing products, research, standards, or knowledge because of their external origins and costs.
我們經(jīng)常為NIH所困:在求解解決方案時,經(jīng)常自認為可以做得更好或者在看到別人的解決方案會提出各種質(zhì)疑.這大都是我們?nèi)狈Ξ敃r問題解決者所面臨限制的認識所造成:可能迫于時間或者預算的限制,也可能受限于當時物理資源的限制.
穿著衣服的猴子
NIH綜合征的特點就是人們會為了證明自己能夠提供更加卓越的解決方案而放棄其他開發(fā)人員已經(jīng)完成的工作.這種狂妄自大的行徑說明此人并無興趣去維護他人竭盡全力提供的最佳成果,也不想以此為基礎去挑戰(zhàn)新的高度.NIH綜合征本質(zhì)上是動物天性—”嘿,我更好”的體現(xiàn),就像所有的公猴都會向母猴證明”我更好”一樣.
放棄已有工作成果而另起爐灶的做法無形之間浪費了大量時間.有一些技術人員在入職新公司后,往往有想推倒一切重來的欲望.我曾經(jīng)有位朋友連續(xù)跳槽很多家公司,每次入職之前都信心滿滿,不就后就黯然離開.朋友能力很不錯,但每次入職后總是急于通過推倒重來來證明自己的能力.
更糟的是,新的解決方案往往只是做了一些改進,和之前并無本質(zhì)區(qū)別,再加上現(xiàn)代的應用往往動輒十幾萬行,遠超出每個人所能注意的極限,這也會讓程序員產(chǎn)生疏漏,從而使得這個問題變得更糟糕.
當然,少數(shù)情況下,新的解決方案更好,這只是因為技術人員早已了解做過的工作,從而針對問題可以提出更高的解決方案.站在現(xiàn)在的角度看歷史,還看不出對錯的話,除非你對歷史一無所知.
為什么Linux會成功
Linux 為什么會成功有很多的的因素,除卻當時環(huán)境因素外,其成功之處在于開源的世界讓每個人都能得到 Linux源碼,從而使得經(jīng)驗可以被借鑒.事實上,在原有軟件基礎上進行擴展是Unix的核心概念之一.當然,在Linux出現(xiàn)之前,借鑒他人編寫的軟件已成為相當普遍的做法,這也是GUN宣言中的GPL下所闡釋的思想.
來自Unix/Linux的編程啟示錄
現(xiàn)在我們來看看 Unix/Linux 中那些隱藏的編程哲學,需要說明的是 Unix/Linux 中的編程哲學非常通俗易懂,他們大多是你已知的,更多的時候是我們不曾注意到.
無論你現(xiàn)在負責的系統(tǒng)多么復雜,這總有可以幫助你的地方.(要說復雜,還有什么比 Unix/Linux 更為復雜的應用?)
原則一:小既是美
我猜當你看到”小既是美”一詞時會首先想到一句諺語”麻雀雖小,五臟俱全”.那就用麻雀做引子來說說為什么小即是美.
大凡生物,無論形體如何,愈小愈穩(wěn)定.麻雀相對人而言,出現(xiàn)腦殘鳥的幾率要小的多,而單細胞生物相對多細胞生物產(chǎn)生顯著變異體的概率也要小的多…在軟件工程中,同樣如此.Unix中的程序大凡遵循這條準則,小帶來的顯著優(yōu)點如下:
易于編寫
易于理解
易于維護
消耗更少的系統(tǒng)資源
容易與其他工具組合
盡管我知道你已經(jīng)對其有過了解,我還是例行的啰嗦一下.
每個程序員心中都有編寫一個萬能軟件的想法,渴望像上帝一樣創(chuàng)世,能夠名垂青史,但這實在是太難了.越是復雜的問題越令人畏縮不前,想想在上學期間,你是更樂于立刻開始做一道題還是一套題呢?不出意外,我們大都喜歡從一道題開始.編寫小程序同樣如此:我們能夠盡快的動手去做,并且針對某個點找出更合理的解決方案.另外,由于大腦的結(jié)構(gòu),我們無法同時關注超過四個以上的點,而復雜的程序需要被關注的點卻遠大于四個,這就意味著我們可能會犯更多的錯誤.
小程序帶來的另一個好處就是容易理解,一個100行的程序比一個1000行的程序要容易理解的多(復雜度相同的情況下).
當程序足夠小的時候它就是函數(shù),還有什么比函數(shù)更靈活地自由組合呢?當然大多數(shù)小程序不能夠小到只有一個函數(shù),但盡可能的減小程序大小仍然很重要,unix/linux中的命令便是最佳的示例:cp用來拷貝,rm用來刪除,組合起來就可以實現(xiàn)移動,簡直棒呆了.
我想,沒人會認為麻雀每天攝入的能量會比人多吧?換到程序當中就是越小的程序消耗的系統(tǒng)資源會更少,大多數(shù)情況下如此.
原則二:讓每個程序只做好一件事情
程序員也許只想編寫一個簡單的應用程序,但是隨著他的創(chuàng)新精神占據(jù)上風,促使他在會在這里添加一個功能,在那里添加一個選項,很快你就發(fā)現(xiàn)本來你只想要一個文本編輯器,但是他卻給你一個IDE,最終他給你的往往不是驚喜而是大雜燴.這個問題不但在程序員身上體現(xiàn)出來,同樣也會出現(xiàn)在產(chǎn)品經(jīng)理上:想要一個計算器對么,我這里有個超級計算機可以給你用?現(xiàn)在你只能面對這這么一個龐然大物了
該思想和”小即是美”相輔相成,”專注一件事”的應用最終會產(chǎn)生一個較小的程序,而小程序往往只有單一的功能,單一功能的程序往往也會很小.另外,每個程序只做一件事情也意味著我們可以集中精力去解決當前任務,全新全意做好本職工作.
原則三:建立原型
原型的建立是學習的過程:在該過程中可以知道哪些想法可行,哪些不可行.每一個正確設計的背后都有數(shù)百個錯誤的設計方案,通過建立原型,我們可以在早期剔除掉不良的設計方案,以此來降低風險.換句話說,越早的建立原型,離你的軟件發(fā)布的時間越近.
你的軟件發(fā)布了嗎?
從開始接觸軟件工程開始起,我們的前輩就告訴我們:”軟件永遠不會有開發(fā)完的時候,記住,是永遠!”.
“怎么會完不成呢,我只要不做了不就行了么?”,現(xiàn)在想想,這比讓一個沉迷在購物中的女人停下腳步更難(如果錢是無盡的話).編寫軟件亦如此,你永遠都會想要加入的更多的功能.想加入的更多功能的可能不是你,或者是你的產(chǎn)品經(jīng)理,當然你的boss也會摻一腳.
我一直在向周圍的朋友傳遞這么一種觀點”世界上唯有不變的事物那就是變“,對于軟件工程同樣如此.既然變化無可避免,那軟件是怎么完成的?盡管我們做事都希望看到最后的結(jié)局,但是對于軟件而言并非如此.可以說,沒有做完的軟件,只有發(fā)布的軟件.
我曾犯過類似的錯誤.16年我在負責一款移動端產(chǎn)品的開發(fā),希望在一個月內(nèi)上線第一個版本.由于個人疏忽,當我著手原型工作時離發(fā)布時間只有20天的時間了,在這期間發(fā)現(xiàn)原有的一些方案無法奏效,我不得不臨時更改一些既有的設計.最終導致第一個版本正式發(fā)布的時間超出15天.我也曾因此被認為是個糟糕的工程師.在團隊沒有任何移動應用產(chǎn)品開發(fā)的經(jīng)驗下,及早的開始建立原型或許不會導致如此后果.在離開這家公司之后,我仍倍感慚愧.
原則四:舍棄高效率而取可移植性
偏向高效率往往會導致代碼不可移植,而選擇可移植性往往會讓軟件的的性能不那么盡如人意.每當有為了追求高效率而放棄移植性的想法的時候,請在心中默念以下兩句話:
1.速度欠佳的缺點會被明天的機器克服
2.好程序不會消失,而被移植到新平臺.
關于優(yōu)化的兩點建議
在unix環(huán)境中,可移植性的含義通常意味著人們要轉(zhuǎn)而采用shell腳本來編寫軟件.拋開平臺不談,關于優(yōu)化,我有以下兩點建議:
不要立刻優(yōu)化:如無必要,無須優(yōu)化.換句話說,不要想當然的優(yōu)化,尤其是在用戶無感覺的情況下.
關注微優(yōu)化:影響性能的往往只有幾處,在需要優(yōu)化的時候只要解決這幾處就好,切莫以優(yōu)化的名義重構(gòu)全部.
原則五:使用純文本來存儲數(shù)據(jù)
文本不一定是性能最好的格式,但卻是最通用的.另外,文本文件易于閱讀和編輯:在任何平臺上我們可以輕松的閱讀文本數(shù)據(jù),或使用標準文本編輯器對其進行編輯.
你可能會考慮到使用純文本文件拖慢了系統(tǒng)的處理速度,并會找出一系列的證據(jù)來證明處理字符串的性能更低.我們承認文本文件確實拖累了系統(tǒng)的性能,但是記住明天系統(tǒng)的機器的性能必將有大幅度的提高.
原則六:利用軟件的杠桿效應
給你一個杠桿,在不考慮杠桿質(zhì)量的前提下,你真的可以撬動地球.一個人精力只有這么多,如果想要取得非凡的成就,你就必須放大自己對這個世界的影響力,這就需要你找到其中的”杠桿點”,也就是關鍵點.
君子性非異也,善假于物也
軟件中的杠桿效應就是要善于利用他人已有成果,具體點就是學會利用他人寫的代碼.在早期,我希望每一行代碼都是從自己手中出來,并以為為傲,并認為這就是所謂的優(yōu)秀的程序員.多年之后,我才明白成為一個優(yōu)秀程序員的關鍵卻和手敲每行代碼并無必要聯(lián)系.
善于利用他人的代碼會給程序員自身增加砝碼.這可能和很多人的認知相違背.查看別人工作并夸口說自己做的更好,不代表你能力更強;推導現(xiàn)有的方案在重來,那只是模仿不是創(chuàng)造.想要解決掉你手中的任務,編寫更多軟件的最好方法就是善于借用別人的成果.和大多程序員一樣,我曾認為親自編寫代碼能帶來”就業(yè)保障”,并將這種做法視為核心競爭力.但實際工作中卻是相反,在實現(xiàn)功能的前提下,企業(yè)往往認為花費時間更少的程序員更具有高效的生產(chǎn)了,你可能對此感到委屈和不解.這里,我想要說的是:認識企業(yè)對你的認識和你對自己認識之間的差異是非常重要的.
如果有可能,請盡量讓你的工作自動化.通過加強自動化工作來利用軟件的杠桿效應能產(chǎn)生巨大的生產(chǎn)力,并且能夠更充分的利用好時間.如果你是個linux開發(fā)者,shell腳本便是你在尋找的杠桿點.
化作春泥更護花
從另外一個角度來說,允許他人使用你的代碼來發(fā)揮杠桿作用.大部分工程師喜歡私藏自己的源代碼,并視為獨一無二,舉世珍寶,仿佛自己的”核武器”.他們認為公開自己的源代碼,自己就失去地位,會被公司所拋棄.
哪些你以為是”核武器”的代碼真的就有如此威力么?要記住:任何一個有著合理思維的正常人都可以編寫出像樣的代碼.更何況,一個有耐心的程序員完全可以將程序反匯編出來,通過一步一的分析,最終發(fā)現(xiàn)其中的蛛絲馬跡.
Linux的開發(fā)人員認為執(zhí)意保留源碼的控制權并無太大必要.現(xiàn)在你發(fā)現(xiàn),盡管你擁有全部的源碼,但卻仍然不能創(chuàng)造出比Linux更成功的操作系統(tǒng).我想這足打消你心中哪點憂慮了.
重新認識自豪感
現(xiàn)在重新認識所謂的自豪感.很多程序員將寫出優(yōu)秀的代碼,使用先進的技術視為自豪感,但我們最終的產(chǎn)出是用來服務用戶的,如果用戶不能滿意,那么我們所謂的自豪感不過是”孤芳自賞”.
原則七:使用shell腳本來提高杠桿效應和可移植性
談起腳本語言,很多工程師覺得腳本太弱了,只能用來編寫簡單的應用無法工程化,并且不少程序員更樂于哪些看起來宏大的?Java?或者 net 應用,甚至有些程序員認為腳本語言算不上一門語言.現(xiàn)實給了我們一巴掌:我們從來沒有想象過?JavaScript?會有如此發(fā)展,以 node 為代表的新型開發(fā)平臺,讓整個 JavaScript 語言變得非常有活力.
那么我們是否也小覷了 shell 這種簡單的腳本語言呢?有很長一段時間我不能正確的認識 shell 是什么,甚至覺得”嗨,這東西好像對我沒什么用,它能用來干什么”.讓我改變想法的恰好是15年的工作經(jīng)歷.
和其他腳本語言(如:Python,JavaScript)一樣,shell腳本 同樣由一個或者多個語句組成,通過調(diào)用本地程序,解釋程序和其他腳本來執(zhí)行任務.shell腳本 將每條指令加載到內(nèi)存執(zhí)行.大部分情況下,這些指令是由無數(shù)的 unix/linux 開發(fā)者事先編寫完成,我們要做的就是用 shell 來間接的利用這些高效,安全的代碼.
比如在 shell 中使用wget命令來下載文件時,我們實際書寫的不過幾行語句,背后支撐我們的確有數(shù)萬行的代碼,如果讓你來用 java 寫一個下載器會需要多少工程量呢,又需要耗費多少時間?現(xiàn)在有些程序員會反駁我:我用 python 寫起來也很快,代碼也不多?那問題來了,python 的運行環(huán)境可不是先天就存在 unix/linux 中的,但是大部分 unix/linux 卻都是支持 shell 的.如果編寫的腳本程序要運行在不同的系統(tǒng)中或者運行在許多設備中,shell 無疑具有更好的移植性,不是么?
如你所想,及時運行
腳本語言有一個先天的優(yōu)勢就是他們是解釋型的語言,運行前不需要事先編譯.先來看看以C語言為代表的編譯型語言,要構(gòu)建一個程序的基本流程如下:
思考->編輯代碼->編譯->測試
而在shell當中,整個過程更短:
思考->編輯->測試
相比 C語言,shell 不存在編譯過程,這帶來的優(yōu)勢就是:無論 shell 的應用規(guī)模多大多復雜,只要你想你就可以運行它觀察它,而無需像 C語言 一樣等待編譯過程結(jié)束后再運行.
shell真的慢嗎?
一些程序員對 shell 執(zhí)行效率過于擔憂,認為其效率太低,這就導致了他們?yōu)榱烁叩男势髨D采用 C語言 來重寫腳本.shell腳本 的執(zhí)行效率相對較慢,一旦 C程序 被裝載到內(nèi)存中運行, 純C程序 與那些從腳本中調(diào)用 C程序 相比,并沒有太大的性能優(yōu)勢.
另外,由于 Unix/Linux 中大部分的命令做過相關的優(yōu)化,反而會比由你編寫的 純C程序 更快.這也引出我想說的另外一點:為了追求更高的性能而更換語言這一做法有待商榷.如果真是為了追求性能,那么改變通過改良實現(xiàn)方法更有效,比如有序數(shù)列中查找指定數(shù)字采用二分查找比傳統(tǒng)的遍歷查找的時間復雜度更低,而不是將原來實現(xiàn)遍歷查找的java代碼改成C代碼實現(xiàn).
原則八:避免強制性的用戶界面
我最早接觸計算機系統(tǒng)是 Windows 2000,應該是在上小學期間,盡管我不知道這個大個”計算器”能夠做什么,但是卻可以在沒人教的情況下琢磨去做,并學會玩編輯文字,利用文本編輯器和共享來相互交流,當然,少不了的紙牌和掃雷.
window和unix/linux理念差異
用戶界面能夠讓任何一個小白在不需要專業(yè)知識的前提邁出操作的第一步.window系列 產(chǎn)品和 unix/linux系列 產(chǎn)品的不同之一在于對于他們對用戶的看法上:window 下的設計者認為用戶是畏懼和計算機打交道的,因而提供足夠的用戶界面來消除用戶的恐懼心理,而unix的設計理念則不同,它認為一個接觸 unix/linux 的用戶已經(jīng)具備了基本的計算機素養(yǎng),并力求更全面的掌握它,從這個角度而言,unix/linux 是選擇用戶的,而 window 是服務用戶的.
這也是早期 window 比 unix/linux 更為大眾所接受的關鍵因素之一.但隨著 unix/linux 的逐漸發(fā)展以及大眾計算機素養(yǎng)的提升,越來越多的人開始接受 unix/linux 產(chǎn)品,并熱衷與此.
像搭積木一樣編程
對于程序員而言,我們希望編程應該像搭積木一樣,通過不同的組合來實現(xiàn)多樣的產(chǎn)品,未來的產(chǎn)品也應該是如此:一些程序員負責開發(fā)基礎的小模塊,另外一些程序員則負責將這些小模塊對接成客戶所需要的產(chǎn)品.對 Unix/Linux 開發(fā)者而言的確如此,我們可以利用系統(tǒng)中提供的眾多非界面性小程序來組合成我們所需要的.但是對于提供用戶界面的小程序而言我們卻很難做到這點:用戶界面渴望與用戶溝通而非另一個程序,而模擬人在用戶界面上的溝通并非易事,你需要花費更多的精力放在非核心需求上.
即使我們能夠模擬,從操作效率來看也不容樂觀.畢竟用戶界面相對命令程序而言本身意味著更多的資源消耗,我想沒人愿意在服務器上裝一個KDE吧?這就是 window 下同樣擁有眾多的小程序但卻很難將其組合成新產(chǎn)品的原因之一,換言之我們很難利用前人已產(chǎn)生的成果來發(fā)揮杠桿作用.
嗨,我們需要再加個按鈕
程序員和產(chǎn)品之間總有一個矛盾點,來看看下面這個對話.
PM:”這里加個按鈕”
RD:”又沒有人用,不加不行么?”
PM:”聽我的,加上吧!加了按鈕之后就會有人點擊…”
RD:”好吧…”
PM:”你看這個地方空白好大,能再加一個按鈕么?”
RD:”我….”
好吧,這是個笑話,我并非想挑起程序員和產(chǎn)品之間的戰(zhàn)爭.如果你在設計/開發(fā)一個界面化的產(chǎn)品,你經(jīng)常會不由自主的為他加上更多的按鈕,企圖讓他提供更豐富的功能:你總覺得有人會需要它.最終導致項目更加復雜,但用戶滿意度卻未見提升.
有這么一件事到現(xiàn)在對我影響甚大.我想把Kindle中的筆記導出到印象筆記,這件事情本來很簡單,只需要導出指定的文本文件,解析后導入到印象筆記就可以.來看看當時我想了什么:我應該做一個界面,可以方便的我操作,別人也可能需要一個保存筆記成html格式的功能,所以我要添加個轉(zhuǎn)換按鈕,當然,保存,導出按鈕也不能忘了,等等…要不要編輯功能?…
這非常好笑,不是么?由于我第一時間想到了圖形界面,接下來不由自主地想在界面上添加更多的功能,更重要的是我明明是自己使用的,卻站在別人的角度上去給自己提了需求?
如果最終呈現(xiàn)出的是圖形化的產(chǎn)品,會發(fā)生很有意思的事情.來想一下,我希望它能在每天十二點自動完成導出任務?難道我要再寫一個程序來模擬點擊操作么?既然這樣,為什么不能讓兩個程序有能夠直接交流的能力么?(感謝unix/linux中的管道機制)
現(xiàn)在來看到底發(fā)生了什么?當我們想提供界面的時候,就假設是人在操作.這個隱形的假設最終讓這個程序失去了自由,好比送給孩子一個用膠水粘合積木而成的城堡而非一盒積木.
原則九:讓每個程序都成為過濾器
程序是什么?早期認為?程序=算法+數(shù)據(jù).但從功能的角度來說,程序即 過濾器.
先不要著急罵我或者反駁我.你不覺得在你編寫的每個程序中,無論是復雜還是簡單,都是以某種形式接受數(shù)據(jù),并產(chǎn)生一些數(shù)據(jù)作為輸出么?這些要輸出的數(shù)據(jù)不就是取決于程序中的算法么?有一些人為過濾器就該是過濾掉不符合期望的東西,而非轉(zhuǎn)換,比如存在一個程序用于過濾掉集合中元素值為0的元素,這對于大部分人而言是最直觀的有關過濾的理解.但要記住過濾器同樣也包含轉(zhuǎn)換的概念.
對于計算器而言,我們輸入錯誤會產(chǎn)生錯誤提示,而決定產(chǎn)生什么樣錯誤信息的算法就是錯誤狀態(tài)輸入的過濾器.可以說算法是人根據(jù)需求定義的規(guī)則,即算法由人定義.那數(shù)據(jù)又是怎么來的?一個沒有數(shù)據(jù)輸入/輸出的程序就像一個不會進食和排泄的人,這種程序沒有存在的價值,現(xiàn)實世界也不存在這種人.
原則十:并行思考
計算機界有個經(jīng)典的笑話:如果一個女人要花是十個月生下一個嬰兒,是否意味著能讓十個女人在一個月內(nèi)生出一個嬰兒呢?笑話中透出的含義非常明顯:自然特性導致某些任務必須被串行,任何試圖讓其并行運行的舉動都無法加快它的進程.
在數(shù)字計算機的整個歷史中,有兩個需求不斷的驅(qū)動我們:一是我們想計算機做的更多,令一個是我們想要計算機運行的更快.而并發(fā)則是實現(xiàn)這兩個需求有效途徑.對程序設計而言,并行思考意味著我們應該盡可能利用CPU運算性能,這也要求我們要對任務進行細致有效的分解,尋找其串行路徑和并行路徑.
現(xiàn)代操作系統(tǒng)通過提供進程,線程及I/O多路復用作為并行思考的實現(xiàn)手段,這里我們對這三者做個簡單的說明:
進程:每個邏輯控制流都是一個進程,由內(nèi)核來調(diào)度和維護.因為進程有獨立的虛擬地址空間,想要和其他控制流通信必須依靠顯示的進程間通信,即我們所說的IPC機制
I/O多路復用:應用程序在一個進程的上下文中顯式地調(diào)度他們自己的邏輯流.邏輯流被模型化為狀態(tài)機,數(shù)據(jù)到達文件描述符之后,主程序顯式地從一個狀態(tài)轉(zhuǎn)換為另一個狀態(tài).因為程序都是以一個單獨的進程,所以所有的流都共享同一個地址空間.基本的思路就是使用select函數(shù)要求內(nèi)核掛起進程,只有一個或多個I/O事件發(fā)生后,才將控制權返回給應用程序
線程:線程應該是我們最為熟知的.它本質(zhì)是運行在一個單一進程上下文中的邏輯流,由內(nèi)核進行調(diào)度.
現(xiàn)代程序設計語言大都提供對這三種開發(fā)方式的支持,比如 C,Node,Python 中常用多進程/線程技術,java中的多線程及NIO技術等等.除此之外,協(xié)程也是一種不錯的技術方案,比如 Lua,Python 中也提供了對協(xié)程的支持.關于這幾種實現(xiàn)并發(fā)編程的技術方案,我將在隨后的文章中去解析.
最后補充一點,無論機器速度快慢,我們都可以將多個機器串聯(lián)在一起,從而得到一個運行速度更快的集群,這就是現(xiàn)代服務器技術核心之一:大凡高性能的服務器應用背后都有集群的身影,而這些集群大都依托于高性能,廉價的 Unix/Linux 平臺.
原則十一:各部分之和大于整體
水泥暮顺、沙子、石子和水個各自的硬度不高,但是混合起來去能得到高硬度的混凝土.這個現(xiàn)實展示了一個很普通的道理就是對不同特性的物質(zhì)進行組合往往能產(chǎn)出令人意外的結(jié)果,這種不遵循數(shù)學上”1+1=2”的規(guī)律卻和化合反應非常類似.
放在軟件工程中同樣如此:通過組合小程序來構(gòu)建集成性的應用程序.這就和我在上文中提到像搭積木一樣編程.深究下來,無論是搭積木還是編程,其中共性就是組合的思想.從原子到分子,從樹木到高樓大廈,從函數(shù)到程序,看似不相關的東西經(jīng)組合產(chǎn)生出意想不到的結(jié)果,在某種意義上,組合的思想是我們?nèi)祟惔竽X最重要的能力之一.
原則十二:尋找90%的解決方案
“金無足赤,人無完人”這朗朗上口的話放在軟件領域卻代表一個不爭的事實:沒有一個軟件能百分百的滿足用戶.說的更直白點,你的軟件在用戶看來總?cè)鄙冱c什么,無論你做出什么努力,這也從另一個角度說明”只有已發(fā)布的軟件而沒有完成的軟件”.
中國郵政 vs 順豐
既然沒有完美的軟件,那對于軟件開發(fā)者而言,有一個非常艱難的決定:”我們該向用戶提供什么”.這是個非常有意思的問題,其答案取決你所開發(fā)軟件的性質(zhì)以及面向的用戶群體.
說到這,就不得不談起中國郵政和順豐速遞.在中國的每個地方,你都可以用中國郵政來收發(fā)快遞,而順豐卻只見于經(jīng)濟發(fā)展不錯的地區(qū).很多人像我一樣曾抱怨過郵政的效率太低,接下來感嘆一句要是有順豐該多好.現(xiàn)在我們客觀的來談談同為快遞這兩者本質(zhì)差異:郵政作為一家國企,在政府的要求下,郵政必須服務所有的人,必須提供100%的解決方案,而順豐作為一家獨立的商業(yè)公司,卻可以選擇性服務,通過專注于高利潤且容易做到的90%.最終的結(jié)果就是我們普遍覺得順豐具有更高的效率.
這其中的關鍵在于我們需要故意忽略哪些代價昂貴,費時費力或難以解決的問題.從商業(yè)的角度來說,這是一種”低投入,高回報”的解決方案.現(xiàn)在我們可以來談談軟件開發(fā)了.無論你是個人開發(fā)者還是商業(yè)軟件公司負責人,都應該考慮這個問題”向用戶提供什么才最有價值”,然后去解決這其中的90%.這可能令很多人不適,但現(xiàn)在互聯(lián)公司最不應該做的就是企圖提供向郵政一樣的100%的服務.提供90%的方案除了能獲得更高的效益之外,還可以幫助聚集你的用戶群體,這也是15年創(chuàng)業(yè)期間最大的感觸之一.
原則十三:層次化思考
層次化思想是什么?說起來很抽象,不如直接的問自己一個問題”金字塔是如何建成的?”如果你的回答是一層一層建成的,那么你可以直接略過本章節(jié)了.
層次化思考并并非新名詞,對大部分程序員而言,”分層”是所有解決方案的指導思想,這里的分層便是層次化思考的結(jié)果.與層次化思考相關的一種分析方法是 AHP(Analytic hierarchy process),即層次分析法.(關于AHP更多的信息就不多講了),它是思考和構(gòu)造復雜系統(tǒng)的一個基本方法,按照該方法設計出的系統(tǒng)具有明顯的層次體系.
現(xiàn)實世界充斥著層次化結(jié)構(gòu),小到細胞結(jié)構(gòu)大到宇宙,從小團隊到跨國公司,其都呈現(xiàn)出層次化結(jié)構(gòu),對計算機軟件而言亦如此.在層次體系中,下層構(gòu)件為上層構(gòu)件提供服務支撐,上層和下層之間的關系就像是方法的”調(diào)用-返回”.采用層次化設計的應用就像金字塔,先有底層構(gòu)件,然后在之上構(gòu)建高層構(gòu)件,相對低層構(gòu)件而言,高層構(gòu)件更容易理解.
可以說,一個系統(tǒng)無論最初采用什么樣的組織方式,最終都會走向分層體系.
我經(jīng)常說的一句話是:無分層不架構(gòu),通俗點就是沒有分層的應用是沒有架構(gòu)可言的.分層結(jié)構(gòu)在計算機世界中無處不在,來看幾個最典型的例子:
ISO/OSI七層網(wǎng)絡模型
WEB應用分層結(jié)構(gòu)
Unix/Linux系統(tǒng)分層結(jié)構(gòu)
Android 系統(tǒng)分層結(jié)構(gòu)
MVC & MVP
除了上述幾個典型示例外,兩種典型的開發(fā)方式 MVC 和 MVP 也都是典型的分層結(jié)構(gòu):
無論是 MVC 還是 MVP,亦或是 MVVM,還是將來出現(xiàn)的什么 M*P,只要記住所有的開發(fā)方式本質(zhì)都是層次思考的結(jié)果,最終呈現(xiàn)分層體系,這就是所謂的萬變不離其中.如果將分層體系和小程序結(jié)合起來,我們可以得到一個更為通用的程序結(jié)構(gòu)設計圖:
總結(jié)
也許你會像我當初一樣納悶這么優(yōu)秀的操作系統(tǒng)就靠這些看起來無比簡單理念引導?事實確是如此,這有點像我們所說的”大道至簡”,復雜的東西簡單做,也是我們解決問題的最重要的一步.
關于Unix/Linux中的編程哲學,我想以上十三條已經(jīng)足夠.其中最有啟發(fā)的應屬”小既是美”,這也是我決定以后不寫長文的原因.
完秀存。捶码。。或链。惫恼。。株扛。尤筐。汇荐。洞就。。掀淘。旬蟋。。革娄。倾贰。。拦惋。匆浙。。厕妖。
文章原創(chuàng)作者GuoLin 書籍推薦
郭林大神原創(chuàng)android 書籍:《第一行代碼 android》