剖析使Go語(yǔ)言高效的5個(gè)特性(4/5): Goroutines

翻譯原文鏈接? ?轉(zhuǎn)帖/轉(zhuǎn)載請(qǐng)注明出處

英文原文鏈接? ?發(fā)表于2014/06/07

Goroutines

Go語(yǔ)言有g(shù)oroutines。它們是Go語(yǔ)言里并發(fā)編程的基石。

首先,我們來(lái)了解goroutines產(chǎn)生的歷史。在一開始,計(jì)算機(jī)只能跑一個(gè)進(jìn)程。然后到了60年代,多進(jìn)程或者說是分時(shí)的概念變得很流行。在一個(gè)分時(shí)系統(tǒng)里,操作系統(tǒng)必須不停地將CPU上運(yùn)行的進(jìn)程進(jìn)行切換。這種切換必須要將當(dāng)前的進(jìn)程狀態(tài)保存下來(lái),并且將下一個(gè)進(jìn)程的狀態(tài)恢復(fù)到CPU上。這個(gè)過程叫進(jìn)程切換(process switching)

進(jìn)程切換主要有三大開銷。首先內(nèi)核需要把當(dāng)前進(jìn)程用到的所有寄存器內(nèi)容保存下來(lái),然后把下一個(gè)進(jìn)程用到的寄存器內(nèi)容恢復(fù)到CPU上。內(nèi)核還需要將CPU上的虛擬內(nèi)存地址到物理內(nèi)存地址的映射清空,因?yàn)樗鼈冎粚?duì)當(dāng)前進(jìn)程來(lái)說是有效的。最后,還有些額外的開銷是操作系統(tǒng)的上下文切換(context switch),以及調(diào)度器對(duì)下一個(gè)使用CPU進(jìn)程的選擇。

現(xiàn)代處理器里有大量的寄存器。我已經(jīng)無(wú)法將它們都寫在一頁(yè)演講幻燈片上。你應(yīng)該大致有概念保存和恢復(fù)它們需要多少時(shí)間里。

進(jìn)程切換可以在一個(gè)進(jìn)程執(zhí)行過程中的任何位置發(fā)生。操作系統(tǒng)需要保存所有這些寄存器,因?yàn)樗恢滥男┘拇嫫魇潜挥玫降?。于是就有了線程的概念。線程從概念上來(lái)說和進(jìn)程是一樣的,但是它們共享同一個(gè)內(nèi)存尋址空間。

因?yàn)榫€程共享了尋址空間,它們比進(jìn)程更加輕量化。所以創(chuàng)建和切換線程更高效。

Goroutines把這個(gè)概念做了進(jìn)一步延伸。

Goroutines的調(diào)度是自發(fā)合作的(cooperatively),而不依賴于內(nèi)核來(lái)管理它們的分時(shí)。Goroutines之間的切換只在一些事先定義好的位置發(fā)生。在這些位置上,會(huì)有一個(gè)對(duì)Go運(yùn)行環(huán)境(runtime)里的調(diào)度器的函數(shù)調(diào)用。編譯器知道哪些寄存器被使用到了并將它們保存下來(lái)。

雖然goroutines的調(diào)度是自發(fā)合作的,但是調(diào)度是由運(yùn)行環(huán)境完成的。Goroutines觸發(fā)調(diào)度的位置包括:

- Channel的發(fā)送和接收操作(當(dāng)這些操作發(fā)生阻塞時(shí))

- Go語(yǔ)句,但是并不保證新的goroutine會(huì)被立刻調(diào)度

- 像文件和網(wǎng)絡(luò)操作這樣的阻塞系統(tǒng)調(diào)用(syscalls)

- 在垃圾回收之后

上面這個(gè)例子顯示了這些會(huì)發(fā)生調(diào)度的位置。

左邊是一個(gè)ReadFile函數(shù)。箭頭表示線程。當(dāng)它執(zhí)行到os.Open的時(shí)候,線程會(huì)被阻塞來(lái)等待文件操作。這時(shí)候調(diào)度器就會(huì)把右邊的goroutine切換到這個(gè)線程上來(lái)。一直運(yùn)行到讀c chan阻塞的時(shí)候,os.Open的調(diào)用已經(jīng)完成,所以調(diào)度器把線程切換回左邊的file.Read函數(shù)繼續(xù)執(zhí)行。然后它被阻塞在了文件的讀寫操作上。調(diào)度器把線程又切換回右邊去運(yùn)行剛才的channel操作。這個(gè)操作現(xiàn)在已經(jīng)不被阻塞,但是現(xiàn)在又要被阻塞在channel發(fā)送上了。最后當(dāng)文件讀操完成的時(shí)候,線程切換回左邊繼續(xù)運(yùn)行。

上圖顯示了底層的runtime.Syscall函數(shù)。os包里的其它函數(shù)都會(huì)用到它。當(dāng)你的代碼需要調(diào)用操作系統(tǒng)接口的時(shí)候,這個(gè)函數(shù)都會(huì)被調(diào)用。這里對(duì)entersyscall的調(diào)用通知了Go的運(yùn)行環(huán)境這個(gè)線程將要被阻塞。這樣,當(dāng)這個(gè)線程被阻塞的時(shí)候,運(yùn)行環(huán)境會(huì)創(chuàng)建出一個(gè)新的線程來(lái)運(yùn)行其它的goroutines。

這樣的好處就是每個(gè)Go進(jìn)程只需要少量的操作系統(tǒng)線程。Go的運(yùn)行環(huán)境來(lái)負(fù)責(zé)將可運(yùn)行的goroutine分配到空閑的操作系統(tǒng)線程上。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 又來(lái)到了一個(gè)老生常談的問題,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問題開始,來(lái)談?wù)劜?..
    tangsl閱讀 4,310評(píng)論 0 23
  • word直接復(fù)制來(lái)了,格式就不改了。至于這門課怎么復(fù)習(xí),只要平時(shí)實(shí)驗(yàn)都認(rèn)真完成、報(bào)告認(rèn)真寫,平時(shí)分都很高;考試的話...
    Jozhn閱讀 4,889評(píng)論 0 8
  • 輕量級(jí)進(jìn)程模型: 用同步IO的方法寫程序的邏輯,第二點(diǎn)是用盡可能多的并發(fā)進(jìn)程來(lái)提升IO并發(fā)的能力。 核心思想,第...
    lifesoul閱讀 2,815評(píng)論 4 1
  • Deployment Strategy of Instagram Jiahao Yang 4/27 https:...
    Novazyyy閱讀 226評(píng)論 0 0
  • 站在街邊 明晃晃的路燈 刺著眼 生生的疼 眼睛努力的睜 依然望不清方向 突然 來(lái)了一場(chǎng)大雨 洗刷著心的憂傷 雨 絮...
    噯笑de女孩閱讀 205評(píng)論 0 1

友情鏈接更多精彩內(nèi)容