瀏覽器進程與線程解惑


原文: https://imweb.io/topic/58e3bfa845e5c13468f567d5

CPU

CPU是計算機的核心,其負責承擔計算機的計算任務。這里我們比喻為一個工廠

進程

學術上說,進程是一個具有一定獨立功能的程序在一個數據集上的一次動態執行的過程,是操作系統進行資源分配和調度的一個獨立單位,是應用程序運行的載體。我們這里將進程比喻為工廠的車間,它代表CPU所能處理的單個任務。任一時刻,CPU總是運行一個進程,其他進程處於非運行狀態。

線程

在早期的操作系統中並沒有線程的概念,進程是能擁有資源和獨立運行的最小單位,也是程序執行的最小單位。任務調度采用的是時間片輪轉的搶占式調度方式,而進程是任務調度的最小單位,每個進程有各自獨立的一塊內存,使得各個進程之間內存地址相互隔離。后來,隨着計算機的發展,對CPU的要求越來越高,進程之間的切換開銷較大,已經無法滿足越來越復雜的程序的要求了。於是就發明了線程,線程是程序執行中一個單一的順序控制流程,是程序執行流的最小單元。這里把線程比喻一個車間的工人,即一個車間可以允許由多個工人協同完成一個任務。

進程和線程的區別和關系

進程是操作系統分配資源的最小單位,線程是程序執行的最小單位。
一個進程由一個或多個線程組成,線程是一個進程中代碼的不同執行路線;
進程之間相互獨立,但同一進程下的各個線程之間共享程序的內存空間(包括代碼段、數據集、堆等)及一些進程級的資源(如打開文件和信號)。

調度和切換:線程上下文切換比進程上下文切換要快得多。

多進程和多線程

多進程:多進程指的是在同一個時間里,同一個計算機系統中如果允許兩個或兩個以上的進程處於運行狀態。多進程帶來的好處是明顯的,比如你可以聽歌的同時,打開編輯器敲代碼,編輯器和聽歌軟件的進程之間絲毫不會相互干擾。

多線程是指程序中包含多個執行流,即在一個程序中可以同時運行多個不同的線程來執行不同的任務,也就是說允許單個程序創建多個並行執行的線程來完成各自的任務。
瀏覽器多進程架構跟現在的很多多線程瀏覽器不一樣,Chrome瀏覽器使用多個進程來隔離不同的網頁。因此在Chrome中打開一個網頁相當於起了一個進程

那么Chrome為什么要使用多進程架構?

在瀏覽器剛被設計出來的時候,那時的網頁非常的簡單,每個網頁的資源占有率是非常低的,因此一個進程處理多個網頁時可行的。然后在今天,大量網頁變得日益復雜。把所有網頁都放進一個進程的瀏覽器面臨在健壯性,響應速度,安全性方面的挑戰。因為如果瀏覽器中的一個tab網頁崩潰的話,將會導致其他被打開的網頁應用。另外相對於線程,進程之間是不共享資源和地址空間的,所以不會存在太多的安全問題,而由於多個線程共享着相同的地址空間和資源,所以會存在線程之間有可能會惡意修改或者獲取非授權數據等復雜的安全問題。

在了解這個知識點線,我們需要先說明下什么是瀏覽器內核。

瀏覽器內核

簡單來說瀏覽器內核是通過取得頁面內容、整理信息(應用CSS)、計算和組合最終輸出可視化的圖像結果,通常也被稱為渲染引擎。從上面我們可以知道,Chrome瀏覽器為每個tab頁面單獨啟用進程,因此每個tab網頁都有由其獨立的渲染引擎實例。

瀏覽器內核是多線程

瀏覽器內核是多線程,在內核控制下各線程相互配合以保持同步,一個瀏覽器通常由以下常駐線程組成:

  • GUI 渲染線程
  • JavaScript引擎線程
  • 定時觸發器線程
  • 事件觸發線程
  • 異步http請求線程

GUI渲染線程

GUI渲染線程負責渲染瀏覽器界面HTML元素,當界面需要重繪(Repaint)或由於某種操作引發回流(reflow)時,該線程就會執行。在Javascript引擎運行腳本期間,GUI渲染線程都是處於掛起狀態的,也就是說被”凍結”了.

Javascript引擎線程

Javascript引擎,也可以稱為JS內核,主要負責處理Javascript腳本程序,例如V8引擎。Javascript引擎線程理所當然是負責解析Javascript腳本,運行代碼。

Javascript是單線程的

Javascript是單線程的, 那么為什么Javascript要是單線程的?

這是因為Javascript這門腳本語言誕生的使命所致:JavaScript為處理頁面中用戶的交互,以及操作DOM樹、CSS樣式樹來給用戶呈現一份動態而豐富的交互體驗和服務器邏輯的交互處理。如果JavaScript是多線程的方式來操作這些UI DOM,則可能出現UI操作的沖突; 如果Javascript是多線程的話,在多線程的交互下,處於UI中的DOM節點就可能成為一個臨界資源,假設存在兩個線程同時操作一個DOM,一個負責修改一個負責刪除,那么這個時候就需要瀏覽器來裁決如何生效哪個線程的執行結果。當然我們可以通過鎖來解決上面的問題。但為了避免因為引入了鎖而帶來更大的復雜性,Javascript在最初就選擇了單線程執行。

GUI 渲染線程 與 JavaScript引擎線程互斥!

由於JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染界面(即JavaScript線程和UI線程同時運行),那么渲染線程前后獲得的元素數據就可能不一致了。因此為了防止渲染出現不可預期的結果,瀏覽器設置GUI渲染線程與JavaScript引擎為互斥的關系,當JavaScript引擎執行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到引擎線程空閑時立即被執行。

JS阻塞頁面加載

從上面我們可以推理出,由於GUI渲染線程與JavaScript執行線程是互斥的關系,當瀏覽器在執行JavaScript程序的時候,GUI渲染線程會被保存在一個隊列中,直到JS程序執行完成,才會接着執行。因此如果JS執行的時間過長,這樣就會造成頁面的渲染不連貫,導致頁面渲染加載阻塞的感覺。

定時觸發器線程

瀏覽器定時計數器並不是由JavaScript引擎計數的, 因為JavaScript引擎是單線程的, 如果處於阻塞線程狀態就會影響記計時的准確, 因此通過單獨線程來計時並觸發定時是更為合理的方案。

事件觸發線程

當一個事件被觸發時該線程會把事件添加到待處理隊列的隊尾,等待JS引擎的處理。這些事件可以是當前執行的代碼塊如定時任務、也可來自瀏覽器內核的其他線程如鼠標點擊、AJAX異步請求等,但由於JS的單線程關系所有這些事件都得排隊等待JS引擎處理。

異步http請求線程

在XMLHttpRequest在連接后是通過瀏覽器新開一個線程請求, 將檢測到狀態變更時,如果設置有回調函數,異步線程就產生狀態變更事件放到 JavaScript引擎的處理隊列中等待處理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM