1. 程式人生 > >協程到底是什麼?看完這個故事明明白白!

協程到底是什麼?看完這個故事明明白白!

神祕使者

“久聞Java語言跨越平臺,框架眾多,不過二十年功夫,就已晉升天下第一程式語言,今日一見,果然名不虛傳吶!”

“使者先生您過獎了,咱們快些走,國王陛下已經等候多時了”

今日,Java帝國朝堂之上迎來了一位神祕的來賓。

 

 

來到大殿之上,只見國王正襟危坐,閉目養神,不怒自威,堂下群臣鹹集,紛紛側目。

“來者何人?”,國王一旁的內侍問到。

“我乃GoLang帝國使者——Goroutine”,使者答道。

 

 

“GoLang帝國?何方番邦小國?寡人竟從未聽聞”,國王閉眼說到。

說罷,群臣皆笑了起來。

“來此所為何事?”,內侍繼續問到。

使者回答:“我此行特為傳道而來”

說完,國王睜開了眼睛,“傳道?我Java帝國乃天下第一程式設計帝國,只有我們傳出去,哪有學別人之道?”

使者不卑不亢,說到:“Java帝國雖如日中天,但卻有一處缺陷,假以時日,必成大患”

“哦,你倒是說說看,如若言語不通,即刻轟出殿去。”,國王厲聲喝到。

“敢問陛下,Java執行緒執行到阻塞函式時,該當如何?”,使者問到。

一旁的執行緒大臣見狀,上前說到:“遇到阻塞那自然要被作業系統掛起,切換到別的執行緒”

“敢問大人,執行緒切換是否需要成本?如果大量執行緒頻繁切換,成本又當如何?”,使者追問到。

“你若關心這個問題,那就不用阻塞函式,通過非同步回撥來進行”,執行緒大臣答道。

使者嘴角上揚,微微一笑,“好一個非同步回撥!非同步回撥確實不用阻塞,不過它有兩宗罪,其一:割裂了原來的程式碼業務邏輯,其二:陷入回撥地獄難以維護”

 

 

“這也不行,那也不行,你這人還真難伺候”,執行緒大臣有些急了。

使者轉身面向國王說到:“啟稟陛下,我有一法,可讓執行緒遇到阻塞函式後不需切換執行緒,也不用非同步回撥還可以繼續執行下去,是高併發開發神技”

國王一聽來了興趣:“哦,還有這種事?說來聽聽”

使者拜了一拜,說到:“執行緒可以在遇到阻塞的地方後,儲存執行的上下文,轉而去執行別處的程式碼。待阻塞的請求完成後,再轉而回去繼續執行”

 

 

國王不解,問到:“什麼叫轉而去執行別處的程式碼?什麼叫回去繼續執行?這函式執行到一半還能中途退出再回來?”

“是的,沒錯!”,使者回答。

此話一出,朝堂上議論紛紛,群臣都露出了鄙夷的笑容。

“簡直荒謬!函式執行從進入到return退出,從來都是一氣呵成,哪有中途執行一半退出,再回來接著執行的道理?簡直聞所未聞!”,一旁的執行緒大臣說到。

使者繼續說到:“一氣呵成?恐怕不是吧?執行緒執行函式中途,遇到時間片用完或者遇到I/O阻塞,就會被作業系統儲存上下文後掛起,切換到其他執行緒。而後等到機會再回過頭繼續執行,不是嗎?”

 

 

執行緒大臣怒斥道:“強詞奪理!你說的這情況是作業系統在排程管理多個執行緒,對咱們的應用層執行緒來說都是透明的,無需關心”

使者沒有退讓,卻問道:“既然作業系統可以排程管理多個執行緒,那為何執行緒不可以排程管理函式的執行?”

群臣再次交頭接耳,議論起來。

“陛下,此番邦使者妖言惑眾,微臣建議即刻逐出大殿,以正視聽!”

國王應允,隨即遣人上前。

不待侍衛上前,使者自行離去,邊走邊說到:“可嘆!堂堂Java帝國,卻容不下一個新技術”

臨別相會

使者心灰意冷,打算離開Java帝國,卻在半道上被人給攔了下來。

“先生請留步,我家主人請先生府上相會”

使者來到府上,原來主人乃當地一富豪鄉紳。

“先生今日在朝堂之事,我已聽說,在下對先生提到的函式執行過程中可中斷和恢復的技術頗有興趣,還請先生不吝賜教”,主人說完拜了一拜。

“賜教不敢當,我此次來Java帝國,所傳之道名叫協程,是一種高併發開發的絕技,可無奈貴國國君與大臣皆不識貨,無功而返,可惜啊,可惜!”,使者嘆息到。

 

 

“協程?這是何物?我只聽說過程序和執行緒,卻是從未聽過協程”

使者起身說到:“執行緒是作業系統抽象出來的執行流,由作業系統統一排程管理。那在一個執行緒中,同樣可以抽象出多個執行流,由執行緒來統一排程管理。這執行緒之上抽象的執行流就是協程”

主人有些不解,問到:“一個執行緒怎麼會有多個執行流呢?”

“這便是我今日在朝堂上說的,執行緒執行函式遇到阻塞後,可以儲存上下文後退出,轉而執行別處的程式碼,這裡就從一個執行流轉向了另外的執行流”,使者解釋到。

主人拍案而起,“原來是這個意思,妙哉,妙哉啊!不過,這執行緒是作業系統在排程管理,那執行緒裡抽象出來的執行流,也就是協程,該怎麼排程管理呢?作業系統可以通過時鐘中斷和系統呼叫進入核心來剝奪執行緒的執行權,那執行緒該如何剝奪協程的執行權來實現排程管理呢?”

 

 

“真是個好問題!執行緒的排程由作業系統來管理,是搶佔式排程。而協程不同,協程需要互相配合,主動交出執行權,這也是協程的名字——協作式程式的來歷”

“主動交出執行權?如何辦到?”,主人追問。

“辦法有很多,比如C++帝國有一協程框架,名叫libco,他通過HOOK關鍵的系統函式來實現排程器的介入”

“那你們Golang是怎麼做的?也是這樣嗎?”

“我們Golang帝國可不一樣,我們先天設計就是支援協程,系統呼叫都被我們封裝好了,應用程式呼叫時遇到需要阻塞的,像是檔案讀寫Read/Write、Sleep我們的排程器就能有機會介入,去執行排程管理了”,使者得意的說到。

 

 

主人思考片刻,問到:“那我們Java該如何實現呢,還請先生賜教”

“你們Java語言,是通過JVM在執行,位元組碼的執行都在JVM的掌控之中,要想實現對應用程式碼執行流的中斷和恢復還不是易如反掌?”,使者說到。

主人點了點頭,若有所思。

新的征程

主人與使者交談甚歡,不知不覺已近黃昏。

主人起身說到:“今蒙先生賜教,大慰平生。還請先生在府上多留時日,我好細細請教。”

使者連連揮手,說到:“我還有要事在身,明日就要離去”

“不知先生欲往何處?”

“聽說C++帝國又要釋出新版本,我打算前往傳道”

主人面露疑惑:“C++帝國不是有libco了嗎?”

“libco終究不是朝廷之物,此番前去,希望可以讓協程納入新的官方標準”

 

 

翌日清晨,使者拜別主人,策馬離去。

不久,Java帝國朝堂上傳來訊息,民間有人推出了協程框架——Quasar,一時朝野震動。

往期TOP5文章

CPU明明8個核,網絡卡為啥拼命折騰一號核?

因為一個跨域請求,我差點丟了飯碗

完了!CPU一味求快出事兒了!

雜湊表哪家強?幾大程式語言吵起來了!

一個HTTP資料包的奇幻之旅