0. Chrome的并發(fā)模型
如果你仔細看了前面的圖,對Chrome的線程和進程框架應該有了個基本的了解。Chrome有一個主進程,稱為Browser進程,它是老大,管理Chrome大部分的日常事務;其次,會有很多Renderer進程,它們?nèi)Φ囟,各管理一組站點的顯示和通信(Chrome在宣傳中一直宣稱一個tab對應一個進程,其實是很不確切的...),它們彼此互不搭理,只和老大說話,由老大負責權(quán)衡各方利益。它們和老大說話的渠道,稱做IPC(Inter-Process Communication),這是Google搭的一套進程間通信的機制,基本的實現(xiàn)后面自會分解。。。
Chrome的進程模型
Google在宣傳的時候一直都說,Chrome是one tab one process的模式,其實,這只是為了宣傳起來方便如是說而已,基本等同廣告,實際療效,還要從代碼中來看。實際上,Chrome支持的進程模型遠比宣傳豐富,你可以參考一下這里 ,簡單的說,Chrome支持以下幾種進程模型:
- Process-per-site-instance:就是你打開一個網(wǎng)站,然后從這個網(wǎng)站鏈開的一系列網(wǎng)站都屬于一個進程。這是Chrome的默認模式。
- Process-per-site:同域名范疇的網(wǎng)站放在一個進程,比如www.google.com和www.google.com/bookmarks就屬于一個域名內(nèi)(google有自己的判定機制),不論有沒有互相打開的關(guān)系,都算作是一個進程中。用命令行--process-per-site開啟。
- Process-per-tab:這個簡單,一個tab一個process,不論各個tab的站點有無聯(lián)系,就和宣傳的那樣。用--process-per-tab開啟。
- Single Process:這個很熟悉了吧,傳統(tǒng)瀏覽器的模式,沒有多進程只有多線程,用--single-process開啟。
關(guān)于各種模式的優(yōu)缺點,官方有官方的說法,大家自己也會有自己的評述。不論如何,至少可以說明,Google不是由于白癡而采取多進程的策略,而是實驗出來的效果。。。
大家可以用Shift+Esc觀察各模式下進程狀況,至少我是觀察失敗了(每種都和默認的一樣...),原因待跟蹤。。。
不論是Browser進程還是Renderer進程,都不只是光桿司令,它們都有一系列的線程為自己打理各種業(yè)務。對于Renderer進程,它們通常有兩個線程,一個是Main thread,它負責與老大進行聯(lián)系,有一些幕后黑手的意思;另一個是Render thread,它們負責頁面的渲染和交互,一看就知道是這個幫派的門臉級人物。相比之下,Browser進程既然是老大,小弟自然要多一些,除了大腦般的Main thread,和負責與各Renderer幫派通信的IO thread,其實還包括負責管文件的file thread,負責管數(shù)據(jù)庫的db thread等等(一個更詳細的列表,參見 這里 ),它們各盡其責,齊心協(xié)力為老大打拼。它們和各Renderer進程的之間的關(guān)系不一樣,同一個進程內(nèi)的線程,往往需要很多的協(xié)同工作,這一坨線程間的并發(fā)管理,是Chrome最出彩的地方之一了。。。
閑話并發(fā)
單進程單線程的編程是最愜意的事情,所看即所得,一維的思考即可。但程序員的世界總是沒有那么美好,在很多的場合,我們都需要有多線程、多進程、多機器攜起手來一齊上陣共同完成某項任務,統(tǒng)稱:并發(fā)(非官方版定義...)。在我看來,需要并發(fā)的場合主要是要兩類:
- 為了更好的用戶體驗。有的事情處理起來太慢,比如數(shù)據(jù)庫讀寫、遠程通信、復雜計算等等,如果在一個線程一個進程里面來做,往往會影響用戶感受,因此需要另開一個線程或進程轉(zhuǎn)到后臺進行處理。它之所以能夠生效,仰仗的是單CPU的分時機制,或者是多CPU協(xié)同工作。在單CPU的條件下,兩個任務分成兩撥完成的總時間,是大于兩個任務輪流完成的,但是由于彼此交錯,更人的感覺更為的自然一些。
- 為了加速完成某項工作。大名鼎鼎的Map/Reduce,做的就是這樣的事情,它將一個大的任務,拆分成若干個小的任務,分配個若干個進程去完成,各自收工后,在匯集在一起,更快的得到最后的結(jié)果。為了達到這個目的,只有在多CPU的情形下才有可能,在單CPU的場合(單機單CPU...),是無法實現(xiàn)的。
在第二種場合下,我們會自然而然的關(guān)注數(shù)據(jù)的分離,從而很好的利用上多CPU的能力;而在第一種場合,我們習慣了單CPU的模式,往往不注重數(shù)據(jù)與行為的對應關(guān)系,導致在多CPU的場景下,性能不升反降。。。
1. Chrome的線程模型
仔細回憶一下我們大部分時候是怎么來用線程的,在我足夠貧瘠的多線程經(jīng)歷中,往往都是這樣用的:起一個線程,傳入一個特定的入口函數(shù),看一下這個函數(shù)是否是有副作用的(Side Effect),如果有,并且還會涉及到多線程的數(shù)據(jù)訪問,仔細排查,在可疑地點上鎖伺候。。。
Chrome的線程模型走的是另一個路子,即,極力規(guī)避鎖的存在。換更精確的描述方式來說,Chrome的線程模型,將鎖限制了極小的范圍內(nèi)(僅僅在將Task放入消息隊列的時候才存在...),并且使得上層完全不需要關(guān)心鎖的問題(當然,前提是遵循它的編程模型,將函數(shù)用Task封裝并發(fā)送到合適的線程去執(zhí)行...),大大簡化了開發(fā)的邏輯。。。
不過,從實現(xiàn)來說,Chrome的線程模型并沒有什么神秘的地方(美女嘛,都是穿衣服比不穿衣服更有盼頭...),它用到了消息循環(huán)的手段。每一個Chrome的線程,入口函數(shù)都差不多,都是啟動一個消息循環(huán)(參見MessagePump類),等待并執(zhí)行任務。而其中,唯一的差別在于,根據(jù)線程處理事務類別的不同,所起的消息循環(huán)有所不同。比如處理進程間通信的線程(注意,在Chrome中,這類線程都叫做IO線程,估計是當初設計的時候誰的腦門子拍錯了...)啟用的是MessagePumpForIO類,處理UI的線程用的是MessagePumpForUI類,一般的線程用到的是MessagePumpDefault類(只討論windows, windows, windows...)。不同的消息循環(huán)類,主要差異有兩個,一是消息循環(huán)中需要處理什么樣的消息和任務,第二個是循環(huán)流程(比如是死循環(huán)還是阻塞在某信號量上...)。下圖是一個完整版的Chrome消息循環(huán)圖,包含處理Windows的消息,處理各種Task(Task是什么,稍后揭曉,敬請期待...),處理各個信號量觀察者(Watcher),然后阻塞在某個信號量上等待喚醒。。。
圖2 Chrome的消息循環(huán)
當然,不是每一個消息循環(huán)類都需要跑那么一大圈的,有些線程,它不會涉及到那么多的事情和邏輯,白白浪費體力和時間,實在是不可饒恕的。因此,在實現(xiàn)中,不同的MessagePump類,實現(xiàn)是有所不同的,詳見下表:
|
MessagePumpDefault |
MessagePumpForIO |
MessagePumpForUI |
是否需要處理系統(tǒng)消息 |
否 |
是 |
是 |
是否需要處理Task |
是 |
是 |
是 |
是否需要處理Watcher |
否 |
是 |
否 |
是否阻塞在信號量上 |
否 |
是 |
是 |
出處:Venus神廟
責任編輯:bluehearts
上一頁 序 下一頁 Chrome的多線程模型 下
◎進入論壇網(wǎng)絡編程版塊參加討論
|