90后“老頭兒”和00后Go小子的硬盤夜話
1、初次見面
雖然這個(gè)目錄中各種編程語言寫的程序?qū)映霾桓F,但Java還是懷念不幸罹難的C老頭兒。他經(jīng)常給同一目錄中的Python ,Ruby說C老頭兒知識(shí)多么淵博,貼近硬件運(yùn)行,速度飛快,能從他身上學(xué)到很多東西等等。
今天目錄里入駐了一個(gè)新家伙,Java一看文件名"hello.go"就知道這是一門新的語言,難道這們語言叫做Go嗎? 用一個(gè)動(dòng)詞作為語言名稱,挺少見的?。?/p>
Java趕緊上網(wǎng)搜索,我賽,這個(gè)小伙子是2009年出生的,都快10歲了,太年輕了。我們這些90后真的成為老家伙了!
一群90后的老家伙們Java, Python, Ruby.....把00后的Go程序團(tuán)團(tuán)圍住,仔細(xì)地打量:“新來的,你有什么本事?”
Go 有點(diǎn)害怕:“你們要干嘛, Ken Thompson, Rob Pike是我親爹 ,你們小心點(diǎn)兒!”
Python悄悄地問Java :“這倆人是什么鬼?”
“孤陋寡聞了吧” Java 其實(shí)也是剛剛上網(wǎng)搜過,現(xiàn)學(xué)現(xiàn)賣:“ Ken Thompson是Unix 和C的創(chuàng)始人,Rob Pike是 UTF-8的設(shè)計(jì)者! 這不是主要的,關(guān)鍵是Google在為這小子站臺(tái)背書。”
大家聽到這小子背景如此深厚,不由得怯了下來。
“按照慣例,新人都要來一個(gè)Hello World,交個(gè)投名狀吧!”
"又來了一個(gè)把類型放到變量名后邊的!" Java一看到這種語法就氣不打一處來!
“Java先生,您JVM平臺(tái)上的Scala和Kotlin不都是如此嗎?” 00后Go小伙兒所知甚多,以己之道還治彼身。
“那倆小子敢到這兒來,我一定把他們痛打一頓,你們的這種語法,總是讓老夫感到真氣逆行!” Java竟然自稱老夫,真是老了。
“好了,消消氣吧,年齡大了,真氣逆行,走火入魔了可不好??!” Python 安慰到。
“不過這小子的變量都得指定類型,看起來也是個(gè)靜態(tài)類型的語言,是我輩中人。” Java感到了一絲安慰。
“誰是你輩中人? 你仔細(xì)再看看這個(gè)變量聲明,根本沒有指定類型,語句后邊連分號(hào)都沒有,和我們Python 才是一家人。” Python 開始和Go 套近乎。
Java “老頭兒”不屑地說:“這點(diǎn)兒小把戲你都不懂? 這是自動(dòng)類型推斷,我們家Kotlin早就玩爛了! 就說那個(gè)name吧,已經(jīng)被聲明為字符串類型了,不能再改動(dòng)了,你把它賦值為一個(gè)整數(shù)試試? 我打賭編譯器一定報(bào)錯(cuò)!”
2、盤問
由于來了一個(gè)靜態(tài)類型同盟軍,Java 對(duì)Go建立了一點(diǎn)好感,他問道:“小伙子,對(duì)于一門語言來說,肯定得有幾種最基本的數(shù)據(jù)結(jié)構(gòu),例如數(shù)組了,列表了,HashMap了,你應(yīng)該內(nèi)置的都有吧?”
“那是自然,現(xiàn)在不是C語言時(shí)代了,語言中都得內(nèi)置常用的數(shù)據(jù)類型,沒有它們?cè)趺椿旖。?rdquo; Go馬上回復(fù)。
“流程控制語句估計(jì)差不多,我也不想看了, 你怎么實(shí)現(xiàn)用戶自定義的類?。?rdquo; Java自居為這個(gè)目錄的老大,代表大家繼續(xù)盤問。
Go說:“很簡(jiǎn)單,我們從C老頭兒那里學(xué)了一個(gè)struct 過來”
一聽說偶像C老頭兒,Java的眼睛就亮了,這語法果然和C差不多。
“嗯? 這只是屬性數(shù)據(jù)啊, 沒有相關(guān)的方法嗎?” Python 不讓Java獨(dú)大,急忙追問。
“簡(jiǎn)單,寫個(gè)方法就行了!”
“方法和屬性分開了,不在一起,好古怪啊!” 大家紛紛叫道。
“我們都有public, private 這樣的權(quán)限限定符,你那里怎么處理?” Ruby 問道。
“我這里很簡(jiǎn)單,如果一個(gè)標(biāo)識(shí)符(如方法,變量等)以大寫字母開頭,就意味著是公開的,別的包的代碼就可以訪問,否則就是私有的!”
大家紛紛驚嘆, 這...這也有點(diǎn)太天馬行空了吧!
“你怎么處理繼承?”
“我這里其實(shí)并沒有繼承,我這里只有組合:”
又是一片驚嘆聲, 大家紛紛拿這種方法和自己的實(shí)現(xiàn)做比較,Java老頭兒想起了面向?qū)ο笤O(shè)計(jì)的一個(gè)重要原則:“優(yōu)先使用組合而不是繼承”, 心里覺得Go的這種思路還是挺不錯(cuò)的。
“那你能實(shí)現(xiàn)多態(tài)嗎?”
“那還用說, 我實(shí)現(xiàn)的方式也很簡(jiǎn)單,不用強(qiáng)制一個(gè)類去實(shí)現(xiàn)一個(gè)接口,只要你擁有和接口一樣的方法就可以當(dāng)做那個(gè)接口來使用!”
“這不就是和我們的Duck Typing 一樣嘛!” Python和Ruby 異口同聲地說,“只要你看起來鴨子,走起路來?yè)u搖晃晃像鴨子,那不管你是否實(shí)現(xiàn)了鴨子的接口,我們就會(huì)認(rèn)為你是個(gè)鴨子!”
3、goroutine
Java不支持Duck Typing , 心里略微不爽,他撇撇嘴說: “這有什么啊,都是一些奇技淫巧。 我問你,你的多線程編程實(shí)現(xiàn)得怎么樣?這才是你能不能在服務(wù)器端,在高并發(fā)的苛刻環(huán)境中活下來的關(guān)鍵!”
Go說:“我沒有多線程!”
沒有線程? 大家都瞪大了眼睛,那你怎么支持并發(fā)啊?
“可是我有g(shù)oroutine, 可以認(rèn)為是一種輕量級(jí)的線程。”
“我說嘛,現(xiàn)代語言怎么可能不支持并發(fā)? 你這個(gè)goroutine有什么特點(diǎn)?” Java問道。
“goroutine和線程很像,就是一段可以運(yùn)行的代碼,你在一個(gè)函數(shù)調(diào)用之前加上關(guān)鍵字go 就啟動(dòng)了一個(gè)goroutine,簡(jiǎn)單不?“
“說說你具體是怎么實(shí)現(xiàn)的?”
“當(dāng)你創(chuàng)建一個(gè)goroutine,它會(huì)被加入到一個(gè)全局的運(yùn)行隊(duì)列當(dāng)中, 然后調(diào)度器會(huì)把他們分配給某個(gè)邏輯處理器,這個(gè)邏輯處理器會(huì)被綁定到唯一的操作系統(tǒng)線程,在上面真正地運(yùn)行g(shù)oroutine,如果一個(gè)邏輯處理器有多個(gè)goroutine要運(yùn)行,那也要就形成隊(duì)列,讓邏輯處理器來調(diào)度執(zhí)行。”
(邏輯處理器可以有多個(gè))
“要是某個(gè)goroutine需要讀寫文件,阻塞了怎么辦?” Java 很關(guān)心這個(gè)問題。
“簡(jiǎn)單,就讓這個(gè)goroutine和邏輯處理器解脫關(guān)聯(lián),直接和系統(tǒng)線程綁定,等到讀寫文件完成以后,在回到某個(gè)邏輯處理器的隊(duì)列去。”
“那你相當(dāng)于自己實(shí)現(xiàn)了一個(gè)線程的調(diào)度器啊” Python 感嘆到。
“是啊,你們不是這么玩的嗎?” Go 反問道。
Java , Python,Ruby 自然不是這么玩的,根本沒有邏輯處理器這個(gè)東西,像Java,會(huì)把用戶空間的線程直接映射到系統(tǒng)的核心線程去執(zhí)行。
“goroutine 雖說是輕量級(jí)的線程,他們之間怎么通信?” Java問道。
“我的創(chuàng)始人發(fā)明了一個(gè)叫做Channel的東西,你可以理解為一個(gè)通道,通過它各個(gè)goroutine就可以發(fā)送、接收數(shù)據(jù)了!”
goroutine其實(shí)就像在程序在用戶空間實(shí)現(xiàn)的線程, 非常地輕量級(jí),所需的空間非常小,切換也發(fā)生在用戶空間,開銷極小。所以非常適合創(chuàng)建大量的goroutine去并發(fā)地執(zhí)行請(qǐng)求。
4、EXE 文件
“咦,這小子生成了一個(gè)hello.exe來運(yùn)行啊。” Ruby觀察得挺仔細(xì)。
原來的C老頭兒也是編譯成exe執(zhí)行的, Ruby的這個(gè)發(fā)現(xiàn)一下子激起了大家的妒忌,因?yàn)檫@里的90后們,無論是Java, Python, Ruby, PHP其實(shí)都有一個(gè)虛擬機(jī)幫他們執(zhí)行程序, 他們都想體驗(yàn)下當(dāng)個(gè)exe,直接在硬件上執(zhí)行那如飛的感覺,奈何是沒有機(jī)會(huì)啊。
Java 有個(gè)好處是Hotspot的虛擬機(jī),能把部分熱點(diǎn)代碼變成機(jī)器指令,在硬件CPU上執(zhí)行,這已經(jīng)讓Java吹噓很多天了,沒想到又來了一個(gè)直接生成exe執(zhí)行的。
Java 想起之前C老頭兒說的指針和內(nèi)存管理的地獄,馬上拋出一個(gè)撒手锏:“你有自動(dòng)內(nèi)存管理嗎?”
這目錄里邊的大部分語言都是由虛擬機(jī)自動(dòng)管理內(nèi)存, 聽到Java這么問,心里又來了一些優(yōu)越感。
“當(dāng)然有了!你只管創(chuàng)建對(duì)象,分配內(nèi)存,垃圾回收Go會(huì)自己做的,我親爹說過,一定要把C語言不好用的地方改進(jìn)了!”
這些把大家震住了,一個(gè)exe程序,又能自動(dòng)管理內(nèi)存,以后我們還有活路嗎?
“你們看,這個(gè)exe文件好大啊。” 有人叫道。
果真如此,一個(gè)小小的hello.exe竟然有1M多,怎么回事?
“我們Go語言默認(rèn)是靜態(tài)鏈接的,那個(gè)exe會(huì)把運(yùn)行時(shí)所需要的所有東西都加進(jìn)去,這樣你就可以把exe復(fù)制到任何地方去運(yùn)行了,多方便! 再說了我們那個(gè)exe文件還包含著垃圾回收不是?”
Java說:“啊,我明白了,其實(shí)你的每個(gè)exe文件當(dāng)中已經(jīng)包含了一個(gè)類似于虛擬機(jī)的runtime對(duì)不對(duì)? 要不然你怎么去自動(dòng)地回收垃圾,進(jìn)行g(shù)oroutine的調(diào)度啊。”
大家伙的優(yōu)越感又恢復(fù)了一點(diǎn)點(diǎn),至少不會(huì)望人項(xiàng)背了。
夜已深,Java做了個(gè)***的總結(jié):“新來的Go小子代碼寫起來有點(diǎn)Python的感覺,簡(jiǎn)潔干練,但骨子中去卻流淌著靜態(tài)類型的血液。他的封裝、繼承、多態(tài)還有g(shù)oroutine都顯得如此與眾不同,但是總能在某個(gè)語言中找到一點(diǎn)影子,雖然能編譯成EXE,性能不錯(cuò),但實(shí)際上也有runtime ??磥硎俏樟瞬簧僬Z言的特點(diǎn)啊。”
大伙紛紛表示贊同,然后就鳥獸散了。