1. 程式人生 > >瀏覽器程序?執行緒?

瀏覽器程序?執行緒?

在生活中,瀏覽器和我們的工作和生活息息相關。做為前端開發,我們程式碼的應用場景往往是在瀏覽器上。瀏覽器對前端的重要性不可一日而語。那麼我們對瀏覽器是否有比較清晰的瞭解呢?什麼是多程序架構瀏覽器?為什麼瀏覽器核心是多執行緒?Javascript是單執行緒又是什麼鬼?程序和執行緒是否分得清楚呢?

1. 程序(process)和執行緒(thread)

程序和執行緒是作業系統的基本概念,許多人會有所瞭解,但不能較為清晰的分辨。 這裡我們需要了解下面幾個點。

1.0.1. CPU

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

1.0.2. 程序

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

1.0.3. 執行緒

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

1.0.4. 程序和執行緒的區別和關係

  • 程序是作業系統分配資源的最小單位,執行緒是程式執行的最小單位。
  • 一個程序由一個或多個執行緒組成,執行緒是一個程序中程式碼的不同執行路線;
  • 程序之間相互獨立,但同一程序下的各個執行緒之間共享程式的記憶體空間(包括程式碼段、資料集、堆等)及一些程序級的資源(如開啟檔案和訊號)。
  • 排程和切換:執行緒上下文切換比程序上下文切換要快得多

2. 多程序和多執行緒

  • 多程序:多程序指的是在同一個時間裡,同一個計算機系統中如果允許兩個或兩個以上的程序處於執行狀態。多程序帶來的好處是明顯的,比如你可以聽歌的同時,開啟編輯器敲程式碼,編輯器和聽歌軟體的程序之間絲毫不會相互干擾。
  • 多執行緒是指程式中包含多個執行流,即在一個程式中可以同時執行多個不同的執行緒來執行不同的任務,也就是說允許單個程式建立多個並行執行的執行緒來完成各自的任務。

3. 瀏覽器多程序架構

跟現在的很多多執行緒瀏覽器不一樣,Chrome瀏覽器使用多個程序來隔離不同的網頁。因此在Chrome中開啟一個網頁相當於起了一個程序

3.0.1. 那麼Chrome為什麼要使用多程序架構?

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

在瞭解這個知識點線,我們需要先說明下什麼是瀏覽器核心

4. 瀏覽器核心

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

5. 瀏覽器核心是多執行緒

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

  • GUI 渲染執行緒
  • JavaScript引擎執行緒
  • 定時觸發器執行緒
  • 事件觸發執行緒
  • 非同步http請求執行緒

6. GUI渲染執行緒

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

7. Javascript引擎執行緒

Javascript引擎,也可以稱為JS核心,主要負責處理Javascript指令碼程式,例如V8引擎。Javascript引擎執行緒理所當然是負責解析Javascript指令碼,執行程式碼。

8. Javascript是單執行緒的

Javascript是單執行緒的, 那麼為什麼Javascript要是單執行緒的?

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

9. GUI 渲染執行緒 與 JavaScript引擎執行緒互斥!

由於JavaScript是可操縱DOM的,如果在修改這些元素屬性同時渲染介面(即JavaScript執行緒和UI執行緒同時執行),那麼渲染執行緒前後獲得的元素資料就可能不一致了。因此為了防止渲染出現不可預期的結果,瀏覽器設定GUI渲染執行緒與JavaScript引擎為互斥的關係,當JavaScript引擎執行時GUI執行緒會被掛起,GUI更新會被儲存在一個佇列中等到引擎執行緒空閒時立即被執行。

10. JS阻塞頁面載入

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

11. 定時觸發器執行緒

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

12. 事件觸發執行緒

當一個事件被觸發時該執行緒會把事件新增到待處理佇列的隊尾,等待JS引擎的處理。這些事件可以是當前執行的程式碼塊如定時任務、也可來自瀏覽器核心的其他執行緒如滑鼠點選、AJAX非同步請求等,但由於JS的單執行緒關係所有這些事件都得排隊等待JS引擎處理。

13. 非同步http請求執行緒

在XMLHttpRequest在連線後是通過瀏覽器新開一個執行緒請求, 將檢測到狀態變更時,如果設定有回撥函式,非同步執行緒就產生狀態變更事件放到 JavaScript引擎的處理佇列中等待處理。