11 | 多任務:進程鹃祖、線程與協(xié)程
到現(xiàn)在為止,我們已經(jīng)介紹了操作系統(tǒng)的存儲管理:內(nèi)存與外存普舆;也已經(jīng)介紹了輸入與輸出設備的管理恬口。
當然,考慮到輸入與輸出設備屬于人機交互范疇沼侣,我們主要會留到下一章 “桌面軟件開發(fā)” 去詳細介紹祖能,這一章,我們僅概要地回顧輸入與輸出設備的需求演進過程蛾洛。
CPU + 存儲 + 輸入與輸出养铸,軟件開發(fā)最基礎的內(nèi)容基本上就都覆蓋到了。 今天開始轧膘,我們就來聊一聊多任務钞螟。
多任務與執(zhí)行體
多任務的需求是隨處可見的。常見的場景谎碍,比如我們想邊工作邊聽音樂鳞滨;又或者我們需要跑一個后臺監(jiān)控程序,以報告隨時可能發(fā)生的異常蟆淀。
那么拯啦,怎么才能做到多任務?
我們先從物理層面看熔任。最早期的 CPU 基本上都是單核的褒链,也就是同一時間只能執(zhí)行一條指令。盡管如此疑苔,大家可能都聽過 “摩爾定律”碱蒙,簡單地說就是,每隔一年半到兩年,同樣的錢能買到的計算力能夠翻一倍赛惩。
這當然不是什么嚴謹?shù)奈锢韺W定律哀墓,更多的是一定歷史時期下的經(jīng)驗之談。早期 CPU 工藝的發(fā)展喷兼,基本上是通過提高電子元器件的密集程度實現(xiàn)的篮绰;但是電子元器件大小總歸有個極限,不可能無限小下去季惯。
那么怎么辦吠各?不能更小的話,那就橫向多鋪幾個勉抓,一顆 CPU 多加幾顆核心贾漏。這樣多核技術就出現(xiàn)了。多核的意思是說藕筋,單核速度我提不上去了纵散,多給你幾個,價格一樣隐圾。
所以物理層面的多任務伍掀,有兩個方法:一個是多顆 CPU,一個是單顆 CPU 多個核心暇藏。
在桌面端蜜笤,大多數(shù)情況用的是后者,因為桌面端的產(chǎn)品(個人計算機盐碱、手機把兔、手表等)還是很在意產(chǎn)品的體積如何盡可能做得更小瓮顽;而服務器領域垛贤,通常同時使用兩者,它更多關注的是如何盡可能提升單臺計算機的計算力密度趣倾。
但如果我們實際就只有一個單核的 CPU聘惦,是否就沒辦法實現(xiàn)多任務呢?
當然可以儒恋。方法是把 CPU 的時間切成一段段時間片善绎,每個時間片只運行某一個軟件。這個時間片給軟件 A诫尽,下一個時間片給軟件 B禀酱。因為時間片很小,我們會感覺這些軟件同時都在運行牧嫉。這種分時間片實現(xiàn)的多任務系統(tǒng)剂跟,我們把它叫分時系統(tǒng)减途。
分時系統(tǒng)的原理說起來比較簡單,把當前任務狀態(tài)先保存起來曹洽,把另一個任務的狀態(tài)恢復鳍置,并把執(zhí)行權交給它即可。這里面涉及的問題有:
- 任務是什么送淆,怎么抽象任務這樣一個概念税产;
- 任務的狀態(tài)都有什么?怎么保存與恢復偷崩;
- 什么時機會發(fā)生任務切換辟拷?
從今天的現(xiàn)實看,任務的抽象并不是唯一的阐斜。大部分操作系統(tǒng)提供了兩套:進程和線程衫冻。有的操作系統(tǒng)還會提供第三套叫協(xié)程(也叫纖程)。
我個人喜歡統(tǒng)一用來 “執(zhí)行體” 一詞來統(tǒng)稱它們谒出。所謂執(zhí)行體隅俘,是指可被 CPU 賦予執(zhí)行權的對象,它至少包含下一個執(zhí)行位置(獲得執(zhí)行權后會從這里開始執(zhí)行)以及其他的運行狀態(tài)到推。
任務的狀態(tài)都有什么考赛?
從 CPU 的角度惕澎,執(zhí)行程序主要依賴的是內(nèi)置存儲:寄存器和內(nèi)存(RAM)莉测,它們構成執(zhí)行體的上下文。
先看寄存器唧喉。寄存器的數(shù)量很少且可枚舉捣卤,我們直接通過寄存器名進行數(shù)據(jù)的存取。
在我們把 CPU 的執(zhí)行權從軟件 A 切換到軟件 B 的時候八孝,要把軟件 A 所有用到的寄存器先保存起來(以便后續(xù)輪到軟件 A 執(zhí)行的時候恢復)董朝,并且把寄存器的值恢復到軟件 B 上一次執(zhí)行時的值,然后才把執(zhí)行權交給軟件 B干跛。
這樣子姜,在軟件 A 和 B 的視角看來,它們好像一直都是獨自在使用 CPU楼入,從未受到過其他軟件的打擾哥捕。
我們再看內(nèi)存(RAM)。CPU 在實模式和保護模式下的內(nèi)存訪問機制完全不同嘉熊,我們分別進行討論遥赚。在實模式下,多個執(zhí)行體同在一個內(nèi)存地址空間阐肤,相互并無干擾(非惡意情況下)凫佛。
在保護模式下讲坎,不同任務可以有不同的地址空間,它主要通過不同的地址映射表來體現(xiàn)愧薛。怎么切換地址映射表晨炕?也是寄存器。
所以厚满,總結就一句話:執(zhí)行體的上下文府瞄,就是一堆寄存器的值。要切換執(zhí)行體碘箍,只需要保存和恢復一堆寄存器的值即可遵馆。無論是進程、線程還是協(xié)程丰榴,都是如此货邓。
進程與線程
那么,不同的執(zhí)行體究竟有何不同四濒?為何會出現(xiàn)不同種類的執(zhí)行體换况?
進程是操作系統(tǒng)從安全角度來說的隔離單位,不同進程之間基于最低授權的原則盗蟆。
在創(chuàng)建一個進程這個事情上戈二,UNIX 偷了一次懶,用的是 fork(分叉)語義喳资。所謂 fork觉吭,就是先 clone 然后再分支,父子進程各干各的仆邓。
這樣創(chuàng)建進程很討巧鲜滩,不用傳遞一堆的參數(shù),使用上非常便利节值。但我認為從架構設計的角度徙硅,這是 UNIX 操作系統(tǒng)設計中最糟糕的 API,沒有之一搞疗。而更不幸的是 Linux 把這一點繼承下來了嗓蘑。
為什么進程 fork 是糟糕的?這是因為:進程是操作系統(tǒng)最基本的隔離單元匿乃,我們怕的就是摘不清楚籍琳,但是 fork 偏偏要藕斷絲連鼠次。
這一點 Windows 要清晰很多,哪些文件句柄在子進程中還要用到,一一明確點名女轿,而不是 fork 一下糊里糊涂就繼承過去了原献。
事實上我個人那么多年工程經(jīng)驗表明坎背,除了會接管子進程的標準輸入和標準輸出,我們幾乎從來不會通過向子進程傳遞文件句柄來通訊柜思。
所以 fork 這種傳遞進程上下文的方式,是徹頭徹尾的一次過度設計巷燥。甚至嚴重一點說赡盘,是設計事故。
線程的出現(xiàn)缰揪,則是因為操作系統(tǒng)發(fā)現(xiàn)同一個軟件內(nèi)還是會有多任務的需求陨享,這些任務處在相同的地址空間,彼此之間相互可以信任钝腺。
從線程角度去理解 UNIX 的 fork抛姑,能夠稍微理解一些設計者們當年的考量。
早期操作系統(tǒng)中沒有線程的概念艳狐,也不會有人想到要搞兩套執(zhí)行體定硝。所以進程實際上承擔了一部分來自線程的需求:我需要父進程的環(huán)境。
協(xié)程與 goroutine
協(xié)程并不是操作系統(tǒng)內(nèi)核提供的毫目,它有時候也被稱為用戶態(tài)線程蔬啡。這是因為協(xié)程是在用戶態(tài)下實現(xiàn)的。如果你感興趣镀虐,也可以自己實現(xiàn)一個箱蟆。
但為什么會出現(xiàn)協(xié)程呢?看起來它要應對的需求與線程一樣刮便,但是功能比線程弱很多空猜?
答案是因為實現(xiàn)高性能的網(wǎng)絡服務器的需要。對于常規(guī)的桌面程序來說诺核,進程 + 線程綽綽有余抄肖。 但對于一個網(wǎng)絡服務器久信,我們可以用下面這個簡單的模型看它:
對網(wǎng)絡服務器來說窖杀,大量的來自客戶端的請求包和服務器的返回包,都是網(wǎng)絡 IO裙士;在響應請求的過程中入客,往往需要訪問存儲來保存和讀取自身的狀態(tài),這也涉及本地或網(wǎng)絡 IO腿椎。
如果這個網(wǎng)絡服務器有很多客戶桌硫,那么整個服務器就充斥著大量并行的 IO 請求。
操作系統(tǒng)提供的標準網(wǎng)絡 IO 有以下這些成本:
- 系統(tǒng)調(diào)用機制產(chǎn)生的開銷啃炸;
- 數(shù)據(jù)多次拷貝的開銷(數(shù)據(jù)總是先寫到操作系統(tǒng)緩存再到用戶傳入的內(nèi)存)铆隘;
- 因為沒有數(shù)據(jù)而阻塞,產(chǎn)生調(diào)度重新獲得執(zhí)行權南用,產(chǎn)生的時間成本膀钠;
- 線程的空間成本和時間成本(標準 IO 請求都是同步調(diào)用掏湾,要想 IO 請求并行只能使用更多線程)。
在一些人心目中會有一個誤區(qū):操作系統(tǒng)的系統(tǒng)調(diào)用很慢肿嘲。這句話很容易被錯誤地理解為系統(tǒng)調(diào)用機制產(chǎn)生的開銷很大融击。
但這是很大的誤解。系統(tǒng)調(diào)用雖然比函數(shù)調(diào)用多做了一點點事情雳窟,比如查詢了中斷向量表(這類似編程語言中的虛函數(shù))尊浪,比如改變 CPU 的執(zhí)行權限(從用戶態(tài)躍遷到內(nèi)核態(tài)再回到用戶態(tài))。
但是注意這里并沒有發(fā)生過調(diào)度行為封救,所以歸根結底還是一次函數(shù)調(diào)用的成本拇涤。怎么理解操作系統(tǒng)內(nèi)核我們示意如下:
從操作系統(tǒng)內(nèi)核的主線程來說,內(nèi)核是獨立進程誉结,但是從系統(tǒng)調(diào)用的角度來說工育,操作系統(tǒng)內(nèi)核更像是一個多線程的程序,每個系統(tǒng)調(diào)用是來自某個線程的函數(shù)調(diào)用搓彻。
為了改進網(wǎng)絡服務器的吞吐能力如绸,現(xiàn)在主流的做法是用 epoll(Linux)或 IOCP(Windows)機制,這兩個機制頗為類似旭贬,都是在需要 IO 時登記一個 IO 請求怔接,然后統(tǒng)一在某個線程查詢誰的 IO 先完成了,誰先完成了就讓誰處理稀轨。
從系統(tǒng)調(diào)用次數(shù)的角度扼脐,epoll 或 IOCP 都是產(chǎn)生了更多次數(shù)的系統(tǒng)調(diào)用。從內(nèi)存拷貝來說也沒有減少奋刽。所以真正最有意義的事情是:減少了線程的數(shù)量瓦侮。
既然不希望用太多的線程,網(wǎng)絡服務器就不能用標準的同步 IO(read/write)來寫程序佣谐。知名的異步 IO 網(wǎng)絡庫 libevent 就是對 epoll 和 IOCP 這些機制包裝了一套跨平臺的異步 IO 編程模型肚吏。
NodeJS 一炮而紅,也是因為把 JavaScript 的低門檻和 libevent 的高性能結合起來狭魂,給了前端程序員一個“我也能搞高性能服務器”的夢想罚攀。
但是異步 IO 編程真的很反人類,它讓程序邏輯因為 IO 異步回調(diào)函數(shù)而碎片化雌澄。我們開始懷念寫同步 IO 的那些日子了斋泄。
讓我們再回頭來看:我們?yōu)槭裁聪M麥p少線程數(shù)量?因為線程的成本高镐牺?我們分析一下炫掐。
首先,我們看下時間成本睬涧。它可以拆解為:
- 執(zhí)行體切換本身的開銷募胃,它主要是寄存器保存和恢復的成本沛厨,可騰挪的余地非常有限;
- 執(zhí)行體的調(diào)度開銷摔认,它主要是如何在大量已準備好的執(zhí)行體中選出誰獲得執(zhí)行權逆皮;
- 執(zhí)行體之間的同步與互斥成本。
我們再看線程的空間成本参袱。它可以拆解為:
- 執(zhí)行體的執(zhí)行狀態(tài)电谣;
- TLS(線程局部存儲);
- 執(zhí)行體的堆棧抹蚀。
空間成本是第一根稻草剿牺。默認情況下 Linux 線程在數(shù) MB 左右,其中最大的成本是堆棧(雖然环壤,線程的堆棧大小是可以設置的晒来,但是出于線程執(zhí)行安全性的考慮,線程的堆棧不能太兄O帧)湃崩。
我們可以算一下,如果一個線程 1MB接箫,那么有 1000 個線程就已經(jīng)到 GB 級別了攒读,消耗太快。
執(zhí)行體的調(diào)度開銷辛友,以及執(zhí)行體之間的同步與互斥成本薄扁,也是一個不可忽略的成本。雖然單位成本看起來還好废累,但是蓋不住次數(shù)實在太多邓梅。
我們想象一下:系統(tǒng)中有大量的 IO 請求,大部分的 IO 請求并未命中而發(fā)生調(diào)度邑滨。另外日缨,網(wǎng)絡服務器的存儲是個共享狀態(tài),也必然伴隨著大量的同步與互斥操作驼修。
綜上殿遂,協(xié)程就是為了這樣兩個目的而來:
- 回歸到同步 IO 的編程模式诈铛;
- 降低執(zhí)行體的空間成本和時間成本乙各。
但是,大部分你看到的協(xié)程(纖程)庫只是一個半吊子幢竹。它們都只實現(xiàn)了協(xié)程的創(chuàng)建和執(zhí)行權的切換耳峦,缺了非常多的內(nèi)容。包括:
- 協(xié)程的調(diào)度焕毫;
- 協(xié)程的同步蹲坷、互斥與通訊驶乾;
- 協(xié)程的系統(tǒng)調(diào)用包裝,尤其是網(wǎng)絡 IO 請求的包裝循签。
這包含太多的東西级乐,基本上你看到的服務端操作系統(tǒng)所需的東西都要包裝一遍。而且县匠,大部分協(xié)程庫风科,連協(xié)程的基礎功能也是半吊子的。這里面最難搞的是堆棧乞旦。
為什么協(xié)程的堆棧是個難題贼穆?因為,協(xié)程的堆棧如果太小則可能不夠用兰粉;而如果太大則協(xié)程的空間成本過高故痊,影響能夠處理的網(wǎng)絡請求的并發(fā)數(shù)。理想情況下玖姑,堆棧大小需要能夠自動適應需要愕秫。
所以,一個完備的協(xié)程庫你可以把它理解為用戶態(tài)的操作系統(tǒng)焰络,而協(xié)程就是用戶態(tài)操作系統(tǒng)里面的 “進程”豫领。
這世界上有完備的協(xié)程庫么?有舔琅。有兩個語言干了這事兒:Erlang 和 Go 語言等恐。Erlang 語言它基于虛擬機,但是道理上是一致的备蚓。Go 語言里面的用戶態(tài) “進程” 叫 goroutine课蔬。它有這樣一些重要設計:
- 堆棧開始很小(只有 4K)郊尝,但可按需自動增長二跋;
- 堅決干掉了 “線程局部存儲(TLS)” 特性的支持,讓執(zhí)行體更加精簡流昏;
- 提供了同步扎即、互斥和其他常規(guī)執(zhí)行體間的通訊手段,包括大家非常喜歡的 channel况凉;
- 提供了幾乎所有重要的系統(tǒng)調(diào)用(尤其是 IO 請求)的包裝谚鄙。
架構師的批判性思維
多任務的需求非常復雜。
為了滿足需要刁绒,人們不只發(fā)明了三套執(zhí)行體:進程闷营、線程和協(xié)程,還發(fā)明了各種五花八門的執(zhí)行體間的通訊機制(可以參考 “08 | 操作系統(tǒng)內(nèi)核與編程接口” 中我們給出的表格)。有一些執(zhí)行體間的通訊機制在逐漸消亡傻盟,退出歷史舞臺速蕊。
操作系統(tǒng)內(nèi)核之中,不乏無數(shù)精妙的設計思想娘赴。但是规哲,前輩們也并非圣賢,也可能會出現(xiàn)一些決策上失誤诽表,留下了諸多后遺癥媳叨。
這非常正常。操作系統(tǒng)內(nèi)核是非常龐大而復雜的基礎軟件关顷。它并不像計算機基礎體系結構糊秆,簡潔優(yōu)雅。
對 CPU 而言议双,統(tǒng)一的痘番、接口一致的輸入輸出設備,到了操作系統(tǒng)這里平痰,它需要依據(jù)每一種設備的需求特性汞舱,抽象出對應的更加用戶友好的使用接口。這個工作既繁重宗雇,又需要極強的預見性昂芜。
而作為后輩的我們,在體會這些精妙的設計思想的同時赔蒲,也要批判性去吸收泌神。日常我們天天依賴于這些基礎架構,受到它們的影響與約束舞虱,這些實在是最佳的學習材料欢际。
結語
今天我們重點介紹了多任務,以及多任務帶來的復雜需求矾兜,由此介紹了進程损趋、線程和協(xié)程等三套執(zhí)行體的設計。后面我們還會分進程內(nèi)和進程間來介紹進程的通訊機制椅寺。
執(zhí)行體的設計浑槽,有非常多值得反思的地方。UNIX 的 fork API 是否是一個好的設計返帕?線程的設計是否成功桐玻?如果線程的設計是優(yōu)良的,是不是就不再有 Go 語言這種在用戶態(tài)重造執(zhí)行體和 IO 子系統(tǒng)的必要性溉旋?
如果你對今天的內(nèi)容有什么思考與解讀畸冲,歡迎給我留言,我們一起討論观腊。如果你覺得有所收獲邑闲,也歡迎把文章分享給你的朋友。感謝你的收聽梧油,我們下期再見苫耸。
精選留言(52)
-
Barry
有一個小建議,能否再每篇文章的最后面預告一下儡陨,下一篇要講的主題褪子。這樣我們跟著主題先思考,等看文章的時候就可以看到作者和自己的想法有什么出入和補充骗村。更有利于吸收
作者回復: 挺好的建議嫌褪,多謝。下一節(jié)我們講 “進程內(nèi)協(xié)同:同步胚股、互斥與通訊”笼痛。
2019-05-21
17
-
kirogiyi
這才是真正的架構師課程,如果不具備這些基礎知識琅拌,很難想象能夠設計出好的軟件系統(tǒng)架構∮б粒現(xiàn)在看到很多懂點技術和懂點產(chǎn)品的人自封為架構師,并沒有去真正抓住軟件架構的本質进宝,實在感到有些汗顏刻坊。
2019-05-21
15
-
一步
對于協(xié)程的概念沒有理解,協(xié)程不也是走系統(tǒng)調(diào)用嗎党晋?走系統(tǒng)調(diào)用不就是走到了系統(tǒng)內(nèi)核態(tài)呢谭胚?后面任務調(diào)度,cpu執(zhí)行指令
作者回復: 協(xié)程不走系統(tǒng)調(diào)用未玻。協(xié)程切換只是寄存器的保存和恢復漏益,所以可以在用戶態(tài)下自己來實現(xiàn)。
2019-05-21
10
-
錢晟龍??龍??
老師深胳,我一直有個問題沒理解到绰疤,計算機在做IO的時候會不會使用CPU,如果會怎樣使用的舞终? 阻塞IO阻塞的時候轻庆,也就是IO進行時,它對應的線程是否已經(jīng)放棄了CPU的執(zhí)行權敛劝? 或者老師建議我查閱什么書籍余爆。。
作者回復: 1夸盟、https://m.baidu.com/sf_edu_wenku/view/3210fec818e8b8f67c1cfad6195f312b3169ebe8
2蛾方、是的,執(zhí)行權會轉移2019-05-29
4
-
youyui
想了解下協(xié)程如何操作寄存器切換CPU上下文的,有沒有什么好的資料可以學習下
作者回復: https://github.com/Tencent/libco
2019-05-29
3
-
王聰 Claire
您好桩砰,問一下epoll的意義在于讓線程數(shù)量變少拓春,是指等待執(zhí)行的線程變少了嗎?是因為都登記然后才能執(zhí)行的機制嗎亚隅?還是其他原因呢硼莽?謝謝。
作者回復: 如果用同步 io煮纵,那么每個并行 io 必然需要需要一個線程懂鸵。epoll 在于讓 io 等待都發(fā)生在相同的地方,相當于線程做了多路 io 復用行疏。
2019-05-24
3
-
大糖果
那可以理解為如果操作系統(tǒng)把線程實現(xiàn)的足夠靈活匆光,輕便,就不需要協(xié)程這個機制了嗎酿联?
作者回復: 我認為是這樣
2019-05-21
3
-
Linuxer
有一個疑問:協(xié)程屬于用戶態(tài)的線程终息,它跟線程之間怎么對應呢?協(xié)程之間也需要切換货葬,那線程切換的那些成本它一樣有啊采幌,沒想明白它的優(yōu)勢在哪
作者回復: 從單位時間成本來說,有一定優(yōu)勢但也不會特別大震桶。主要少掉的代價是從用戶態(tài)到內(nèi)核態(tài)再回到用戶態(tài)的成本休傍。這種差異類似于系統(tǒng)調(diào)用和普通函數(shù)調(diào)用的差異。因為高性能服務器上io次數(shù)實在太多了蹲姐,所以單位成本上能夠少一點磨取,積累起來也是很驚人的。
2019-05-21
3
-
fjpcode
多路IO復用: 讓IO的等待都發(fā)生在相同的地方柴墩。 用了不少忙厌,今天才終于弄理解清楚為啥叫 '多路IO復用'。
2019-05-25
2
-
Geek_03056e
有幾個問題請教一下老師:
1 cpu時間片運行執(zhí)行體江咳,選擇執(zhí)行體時逢净,是cpu控制,還是操作系統(tǒng)控制歼指?進程爹土、線程、協(xié)程獲得的概率是一樣的嗎踩身?
2 通過sh胀茵,cpu知道了進程的首地址,執(zhí)行進程挟阻,這個線程是怎么執(zhí)行的呢琼娘?
3 文中提到網(wǎng)絡服務器的存儲是個共享狀態(tài)峭弟,這個存儲指哪些存儲呢?作者回復: 1脱拼、文章中有表格瞒瘸,里面的調(diào)度方就是你說的控制方。不同執(zhí)行體控制方不一樣挪拟,調(diào)度算法不一樣挨务,概率也就不一樣击你。
2玉组、線程知道函數(shù)地址就行,一樣是入口丁侄。
3惯雳、共享存儲包括內(nèi)存、數(shù)據(jù)庫等等鸿摇。2019-05-21
2
-
韓春亮
“在創(chuàng)建一個進程這個事情上石景,UNIX 偷了一次懶,用的是 fork(分叉)語義拙吉。所謂 fork潮孽,就是先 clone 然后再分支,父子進程各干各的筷黔⊥罚”這句話不太理解,希望老師幫忙指點一下
作者回復: 可以查一下fork相關的資料佛舱,這個api很經(jīng)典椎例,有很多介紹材料
2019-05-21
2
-
閆飛
這里對NodeJS部分的引述有點小錯誤,它本身厲害的地方應該是爭取了很多不想學習底層C/C++語言又喜歡得到高性能的"懶惰"的程序員请祖。它的底層是由v8解釋器和基于用戶代碼單事件循環(huán)調(diào)用的libev調(diào)度框架組成订歪。
可惜的是遇到復雜的事件循環(huán)堵死的情況,不理解這些底層原理的流水線JS程序員依然不能很快找到解決方案肆捕。碰到一些封裝了第三方C庫的運算復雜度高的代碼刷晋,F(xiàn)FI接口反而隱藏了更大的問題。
至于異步編程回調(diào)麻煩的問題慎陵,其實編程語言也在另外一個緯度上封裝異步原語眼虱,通過promise/await等高級抽象緩解回調(diào)地獄困境。
2019-06-06
1
-
行者
不太理解協(xié)程的是怎么做到文中提到的兩個優(yōu)勢的荆姆。只是看了一下python的協(xié)程蒙幻,能理解它能減少執(zhí)行體切換的時間成本(因為全在用戶態(tài)中),但它的執(zhí)行本質上就是串行執(zhí)行呀胆筒,只是不同的子程序有了更多的入口而已邮破,那怎么做到加速呢诈豌?
作者回復: python的協(xié)程是比較狹義的,它只是一種編程模式抒和,并不算執(zhí)行體矫渔。你可以了解一下Go語言的goroutine。
2019-05-23
1
-
賈志猛
感覺進程與子進程的關系還不是很清楚摧莽,如果父進程執(zhí)行結束后庙洼,子進程會怎樣?子進程結束后镊辕,父進程會怎樣油够?
作者回復: 不會相互影響
2019-05-21
1
-
keshawn
1. UNIX的fork API clone父進程,減少參數(shù)的傳遞征懈∈В看起來和面向對象當初設計的繼承一樣,當初設計的時候覺得會簡化編程卖哎,經(jīng)過大量的實踐之后會發(fā)現(xiàn)耦合越來越嚴重鬼悠。
2. 線程的設計是否成功不好評價,協(xié)程相比線程的改進主要有以下幾點:
1)堆棧按需增長(線程是否也能如此實現(xiàn)亏娜?)
2)去除線程局部存儲焕窝,線程之所以提供線程局部存儲是為了減少參數(shù)傳遞吧(比如ThreadLocal)?
3)調(diào)度方由操作系統(tǒng)內(nèi)核變成了用戶態(tài)维贺,用戶態(tài)實現(xiàn)上和操作系統(tǒng)內(nèi)核要做的調(diào)度應該沒太多本質區(qū)別它掂,但是節(jié)省了系統(tǒng)調(diào)用的成本?2019-05-21
1
-
靠人品去贏
從來沒有看過將CPU內(nèi)部的寄存器的角度來看待程序的執(zhí)行幸缕,比如A切換到B群发,保存A的寄存器值(貌似文中有一次筆誤,保存寄存器應該是保存寄存器的值发乔。)然后恢復B上一次寄存器的值熟妓。這個切換的過程結束怎么判定?
是不是根據(jù)虛擬內(nèi)存頁轉換的物理內(nèi)存頁的數(shù)據(jù)栏尚,讀完寫完就完事了起愈。感覺這個寄存器開始來看操作系統(tǒng)的調(diào)度,終于從這個死記硬背進程線程概念更明白了些译仗,包括CPU寄存器怎么工作(之前計算機原理學的不扎實抬虽,只知道里面都是這個東西而已)。作者回復: > 這個切換的過程結束怎么判定纵菌?
最后一個切換的寄存器是指令執(zhí)行的當前位置(EIP)阐污,改了 EIP 后,CPU 就跳轉到新的地方執(zhí)行咱圆,進程切換了笛辟。2019-05-21
1
-
涵
請問老師青牛云在服務器OS方面是什么思路?打算開發(fā)專門的OS嗎功氨?還是linux就夠用了?
作者回復: 基本上 linux 夠用了
2019-05-21
1
-
涵
請問老師目前云平臺使用的服務器通常運行的是傳統(tǒng)的操作系統(tǒng),例如linux手幢,還是專門為云服務器開放的操作系統(tǒng)呢?如您所說傳統(tǒng)操作系統(tǒng)也有不完善的地方捷凄,或者不適用于多臺服務器集群式提供計算能力的地方。那么針對云服務的服務器是否有專門的操作系統(tǒng)呢?謝謝围来。
作者回復: 有跺涤,CoreOS 想做這事,不過還不太成功监透,國內(nèi)用 CoreOS 我觀察下來應該是完全忽略不計桶错。
2019-05-21
1
-
Aaron Cheung
打卡11 多任務非常深入
2019-05-21
1
-
大王叫我來巡山
有個詞叫積重難返,這是我在某大企業(yè)最深刻的感受才漆,我感覺操作系統(tǒng)的設計與演化也是一樣的牛曹,非常感謝許老師佛点,讓我對軟件設計有全新的體會
2019-05-21
1
收起評論