這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。1初次見面
雖然這個目錄中各種程式設計語言寫的程式層出不窮,但Java還是懷念不幸罹難的C老頭兒。他經常給同一目錄中的Python ,Ruby說C老頭兒知識多麼淵博,貼近硬體運行,速度飛快,能從他身上學到很多東西等等。
(老劉註:參加《C老頭兒和Java小子的硬碟夜話》)
今天目錄裡入駐了一個新傢伙,Java一看檔案名稱"hello.go"就知道這是一門新的語言,難道這們語言叫做Go嗎? 用一個動詞作為語言名稱,挺少見的啊!
Java趕緊上網搜尋,我賽,這個小夥子是2009年出生的,都快10後了,太年輕了。我們這些90後真的成為老傢伙了!
一群90後的老傢伙們Java, Python, Ruby.....把00後的Go程式團團圍住,仔細地打量:“新來的,你有什麼本事?”
Go 有點害怕:“你們要幹嘛, Ken Thompson, Rob Pike是我親爹 ,你們小心點兒!”
Python悄悄地問Java :“這倆人是什麼鬼?”
“孤陋寡聞了吧” Java 其實也是剛剛上網搜過,現學現賣:“ Ken Thompson是Unix 和C的創始人,Rob Pike是 UTF-8的設計者! 這不是主要的,關鍵是Google在為這小子月台背書。”
大家聽到這小子背景如此深厚,不由得怯了下來。
“按照慣例,新人都要來一個Hello World,交個投名狀吧!”
"又來了一個把類型放到變數名後邊的!" Java一看到這種文法就氣不打一處來!
“Java先生,您JVM平台上的Scala和Kotlin不都是如此嗎?” 00後Go小夥兒所知甚多,以己之道還治彼身。
“那倆小子敢到這兒來,我一定把他們痛打一頓,你們的這種文法,總是讓老夫感到真氣逆行!” Java竟然自稱老夫,真是老了。
“好了,消消氣吧,年齡大了,真氣逆行,走火入魔了可不好啊!” Python 安慰到。
“不過這小子的變數都得指定類型,看起來也是個靜態類型的語言,是我輩中人。” Java感到了一絲安慰。
“誰是你輩中人? 你仔細再看看這個變數聲明,根本沒有指定類型,語句後邊連分號都沒有,和我們Python 才是一家人。” Python 開始和Go 套近乎。
Java “老頭兒”不屑地說:“這點兒小把戲你都不懂? 這是自動類型推斷,我們家Kotlin早就玩爛了! 就說那個name吧,已經被聲明為字串類型了,不能再改動了,你把它賦值為一個整數試試? 我打賭編譯器一定報錯!”
2盤問
由於來了一個靜態類型同盟軍,Java 對Go建立了一點好感,他問道:“小夥子,對於一門語言來說,肯定得有幾種最基本的資料結構,例如數組了,列表了,HashMap了,你應該內建的都有吧?”
“那是自然,現在不是C語言時代了,語言中都得內建常用的資料類型,沒有它們怎麼混江湖啊!” Go馬上回複。
“流程式控制制語句估計差不多,我也不想看了, 你怎麼實現使用者自訂的類啊?” Java自居為這個目錄的老大,代表大家繼續盤問。
Go說:“很簡單,我們從C老頭兒那裡學了一個struct 過來”
一聽說偶像C老頭兒,Java的眼睛就亮了,這文法果然和C差不多。
“嗯? 這隻是屬性資料啊, 沒有相關的方法嗎?” Python 不讓Java獨大,急忙追問。
“簡單,寫個方法就行了!”
“方法和屬性分開了,不在一起,好古怪啊!” 大家紛紛叫道。
“我們都有public, private 這樣的許可權限定符,你那裡怎麼處理?” Ruby 問道。
“我這裡很簡單,如果一個標識符(如方法,變數等)以大寫字母開頭,就意味著是公開的,別的包的代碼就可以訪問,否則就是私人的!”
大家紛紛驚歎, 這...這也有點太天馬行空了吧!
“你怎麼處理繼承?”
“我這裡其實並沒有繼承,我這裡只有組合:”
又是一片驚歎聲, 大家紛紛拿這種方法和自己的實現做比較,Java老頭兒想起了物件導向設計的一個重要原則:“優先使用組合而不是繼承”, 心裡覺得Go的這種思路還是挺不錯的。
“那你能實現多態嗎?”
“那還用說, 我實現的方式也很簡單,不用強制一個類去實現一個介面,只要你擁有和介面一樣的方法就可以當做那個介面來使用!”
“這不就是和我們的Duck Typing 一樣嘛!” Python和Ruby 異口同聲地說,“只要你看起來鴨子,走起路來搖搖晃晃像鴨子,那不管你是否實現了鴨子的介面,我們就會認為你是個鴨子!”
3goroutine
Java不支援Duck Typing , 心裡略微不爽,他撇撇嘴說: “這有什麼啊,都是一些奇技淫巧。 我問你,你的多線程編程實現得怎麼樣?這才是你能不能在伺服器端,在高並發的苛刻環境中活下來的關鍵!”
Go說:“我沒有多線程!”
沒有線程? 大家都瞪大了眼睛,那你怎麼支援並發啊?
“可是我有goroutine, 可以認為是一種輕量級的線程。”
“我說嘛,現代語言怎麼可能不支援並發? 你這個goroutine有什麼特點?” Java問道。
“goroutine和線程很像,就是一段可以啟動並執行代碼,你在一個函數調用之前加上關鍵字go 就啟動了一個goroutine,簡單不?“
“說說你具體是怎麼實現的?”
“當你建立一個goroutine,它會被加入到一個全域的運行隊列當中, 然後調度器會把他們分配給某個邏輯處理器,這個邏輯處理器會被綁定到唯一的作業系統線程,在上面真正地運行goroutine,如果一個邏輯處理器有多個goroutine要運行,那也要就形成隊列,讓邏輯處理器來調度執行。”
(邏輯處理器可以有多個)
“要是某個goroutine需要讀寫檔案,阻塞了怎麼辦?” Java 很關心這個問題。
“簡單,就讓這個goroutine和邏輯處理器解脫關聯,直接和系統線程綁定,等到讀寫檔案完成以後,在回到某個邏輯處理器的隊列去。”
“那你相當於自己實現了一個線程的調度器啊” Python 感歎到。
“是啊,你們不是這麼玩的嗎?” Go 反問道。
Java , Python,Ruby 自然不是這麼玩的,根本沒有邏輯處理器這個東西,像Java,會把使用者空間的線程直接映射到系統的核心線程去執行。
“goroutine 雖說是輕量級的線程,他們之間怎麼通訊?” Java問道。
“我的創始人發明了一個叫做Channel的東西,你可以理解為一個通道,通過它各個goroutine就可以發送、接收資料了!”
goroutine其實就像在程式在使用者空間實現的線程, 非常地輕量級,所需的空間非常小,切換也發生在使用者空間,開銷極小。所以非常適合建立大量的goroutine去並發地執行請求。
4EXE 檔案
“咦,這小子產生了一個hello.exe來運行啊。” Ruby觀察得挺仔細。
原來的C老頭兒也是編譯成exe執行的, Ruby的這個發現一下子激起了大家的妒忌,因為這裡的90後們,無論是Java, Python, Ruby, PHP其實都有一個虛擬機器幫他們執行程式, 他們都想體驗下當個exe,直接在硬體上執行那如飛的感覺,奈何是沒有機會啊。
Java 有個好處是Hotspot的虛擬機器,能把部分熱點代碼變成機器指令,在硬體CPU上執行,這已經讓Java吹噓很多天了,沒想到又來了一個直接產生exe執行的。
Java 想起之前C老頭兒說的指標和記憶體管理的地獄,馬上拋出一個撒手鐧:“你有自動記憶體管理嗎?”
這目錄裡邊的大部分語言都是由虛擬機器自動管理記憶體, 聽到Java這麼問,心裡又來了一些優越感。
“當然有了!你只管建立對象,分配記憶體,記憶體回收Go會自己做的,我親爹說過,一定要把C語言不好用的地方改進了!”
這些把大家震住了,一個exe程式,又能自動管理記憶體,以後我們還有活路嗎?
“你們看,這個exe檔案好大啊。” 有人叫道。
果真如此,一個小小的hello.exe竟然有1M多,怎麼回事?
“我們Go語言預設是靜態連結的,那個exe會把運行時所需要的所有東西都加進去,這樣你就可以把exe複製到任何地方去運行了,多方便! 再說了我們那個exe檔案還包含著記憶體回收不是?”
Java說:“啊,我明白了,其實你的每個exe檔案當中已經包含了一個類似於虛擬機器的runtime對不對? 要不然你怎麼去自動地回收垃圾,進行goroutine的調度啊。”
大傢伙的優越感又恢複了一點點,至少不會望人項背了。
夜已深,Java做了個最後的總結:“新來的Go小子代碼寫起來有點Python的感覺,簡潔幹練,但骨子中去卻流淌著靜態類型的血液。他的封裝、繼承、多態還有goroutine都顯得如此與眾不同,但是總能在某個語言中找到一點影子,雖然能編譯成EXE,效能不錯,但實際上也有runtime 。看來是吸收了不少語言的特點啊。”
大夥紛紛表示贊同,然後就鳥獸散了。
(完)
你看到的只是冰山一角, 更多精彩文章,請移步《2016文章精華》或者《2017上半年文章精華》
碼農翻身
用故事講述技術