1. 關(guān)于協(xié)程,,究竟有什么用? 一個(gè)例子,,微信在當(dāng)用戶量達(dá)到1億級(jí)別時(shí)候,,在重構(gòu)后臺(tái),有兩種方式: a. 線程式異步改造,; b. 協(xié)程式異步改造 第一種方案無(wú)異于大量徹底重構(gòu),,而第二種可以改少量得代碼即可實(shí)現(xiàn),同步轉(zhuǎn)異步,。 對(duì)于微信這樣量級(jí)這么大的系統(tǒng),,同時(shí)后臺(tái)也是極其復(fù)雜,最后微信選擇了第二種,所以這里說協(xié)程,,究竟有什么用,? 同步改異步,或者說用同步的方式實(shí)現(xiàn)異步,。 2. 對(duì)于協(xié)程比線程有什么好處,? 協(xié)程可以說是“線程的線程”,也就是他不像線程切換時(shí)需要上下文切換,; 協(xié)程就是在一個(gè)線程中最大化利用cpu,,因?yàn)楫?dāng)遇到io阻塞或jdbc阻塞時(shí)候,其實(shí)cpu是空閑的,,一直在等待io返回,,這也是為什么總說數(shù)據(jù)庫(kù)是瓶頸的原因,而這個(gè)時(shí)候,,協(xié)程就是可以讓cpu在此時(shí)繼續(xù)去做運(yùn)算,,而這正是比線程好的地方。 3. 關(guān)于協(xié)程,,你可能看的最多的就是這樣一句話“協(xié)程就是用戶態(tài)的線程”. 要理解是什么是“用戶態(tài)的線程”,,必然就要先理解什么是“內(nèi)核態(tài)的線程”。 內(nèi)核態(tài)的線程是由操作系統(tǒng)來進(jìn)行調(diào)度的,,在切換線程上下文時(shí),,要先保存上一個(gè)線程的上下文,然后執(zhí)行下一個(gè)線程,,當(dāng)條件滿足時(shí),,切換回上一個(gè)線程,并恢復(fù)上下文,。 協(xié)程也是如此,,只不過,用戶態(tài)的線程不是由操作系統(tǒng)來調(diào)度的,,而是由程序員來調(diào)度的,,是在用戶態(tài)的。 yield這個(gè)關(guān)鍵字就是用來產(chǎn)生中斷, 并保存當(dāng)前的上下文的, 比如說程序的一段代碼是訪問遠(yuǎn)程服務(wù)器,,那這個(gè)時(shí)候CPU就是空閑的,,就用yield讓出CPU,接著執(zhí)行下一段的代碼,,如果下一段代碼還是訪問除CPU以外的其它資源,,還可以調(diào)用yield讓出CPU. 繼續(xù)往下執(zhí)行,這樣就可以用同步的方式寫異步的代碼了. 4. 一開始大家想要同一時(shí)間執(zhí)行那么三五個(gè)程序,,大家能一塊跑一跑,。特別是UI什么的,,別一上計(jì)算量比較大的玩意就跟死機(jī)一樣。于是就有了并發(fā),,從程序員的角度可以看成是多個(gè)獨(dú)立的邏輯流,。內(nèi)部可以是多cpu并行,也可以是單cpu時(shí)間分片,,能快速的切換邏輯流,,看起來像是大家一塊跑的就行。 但是一塊跑就有問題了,。我計(jì)算到一半,,剛把多次方程解到最后一步,,你突然插進(jìn)來,,我的中間狀態(tài)咋辦,我用來儲(chǔ)存的內(nèi)存被你覆蓋了咋辦,?所以跑在一個(gè)cpu里面的并發(fā)都需要處理上下文切換的問題,。進(jìn)程就是這樣抽象出來個(gè)一個(gè)概念,搭配虛擬內(nèi)存,、進(jìn)程表之類的東西,,用來管理獨(dú)立的程序運(yùn)行、切換,。 后來一電腦上有了好幾個(gè)cpu,,好咧,大家都別閑著,,一人跑一進(jìn)程,。就是所謂的并行。 因?yàn)槌绦虻氖褂蒙婕按罅康挠?jì)算機(jī)資源配置,,把這活隨意的交給用戶程序,,非常容易讓整個(gè)系統(tǒng)分分鐘被搞跪,資源分配也很難做到相對(duì)的公平,。所以核心的操作需要陷入內(nèi)核(kernel),,切換到操作系統(tǒng),讓老大幫你來做,。 有的時(shí)候碰著I/O訪問,,阻塞了后面所有的計(jì)算??罩彩强罩?,老大就直接把CPU切換到其他進(jìn)程,讓人家先用著,。當(dāng)然除了I\O阻塞,,還有時(shí)鐘阻塞等等,。一開始大家都這樣弄,后來發(fā)現(xiàn)不成,,太慢了,。為啥呀,一切換進(jìn)程得反復(fù)進(jìn)入內(nèi)核,,置換掉一大堆狀態(tài),。進(jìn)程數(shù)一高,大部分系統(tǒng)資源就被進(jìn)程切換給吃掉了,。后來搞出線程的概念,,大致意思就是,這個(gè)地方阻塞了,,但我還有其他地方的邏輯流可以計(jì)算,,這些邏輯流是共享一個(gè)地址空間的,不用特別麻煩的切換頁(yè)表,、刷新TLB,,只要把寄存器刷新一遍就行,能比切換進(jìn)程開銷少點(diǎn),。 如果連時(shí)鐘阻塞,、 線程切換這些功能我們都不需要了,自己在進(jìn)程里面寫一個(gè)邏輯流調(diào)度的東西,。那么我們即可以利用到并發(fā)優(yōu)勢(shì),,又可以避免反復(fù)系統(tǒng)調(diào)用,還有進(jìn)程切換造成的開銷,,分分鐘給你上幾千個(gè)邏輯流不費(fèi)力,。這就是用戶態(tài)線程。 從上面可以看到,,實(shí)現(xiàn)一個(gè)用戶態(tài)線程有兩個(gè)必須要處理的問題:一是碰著阻塞式I\O會(huì)導(dǎo)致整個(gè)進(jìn)程被掛起,;二是由于缺乏時(shí)鐘阻塞,進(jìn)程需要自己擁有調(diào)度線程的能力,。如果一種實(shí)現(xiàn)使得每個(gè)線程需要自己通過調(diào)用某個(gè)方法,,主動(dòng)交出控制權(quán)。那么我們就稱這種用戶態(tài)線程是協(xié)作式的,,即是協(xié)程,。 本質(zhì)上協(xié)程就是用戶空間下的線程。
|
|