不廢話先上題,請問以下程式 conosole.log
的順序?
const https = require('https'); |
- 執行結果
為什麼會有此結果?
第一個點我需要了解到 node 底層使用了 Libuv 處理檔案讀寫和計算 hash 等功能,Libuv 用了Thread Pool 中的 Thread 來處理這些任務,Thread Pool 預設的 Thread 數量為 4 個,換句話說只有 4 個 Libuv 負責的任務可以同時進行,然後 https 請求不是由 Libuv 負責,而是 OS 負責,OS 會決定是否開一條新的 Thread 來處理此任務,因此我們就看到了 HTTPS 請求最快完成,但是問題來了,為什麼 fs module 檔案讀了這麼久?
那我們需要先了解讀檔案的流程
上圖我們可以看到, node 沒有直接發 request 去讀檔案,而是在第二步時,先取得該檔案的狀態資訊,才後才在第四步發 request 去讀檔案
我們來看執行的方式
一開始 fs, PBKDF2 1 ~ 3 號就將 Thread Pool 直接佔滿了,然後 Thread #1 發了 Request 去取得該檔案的狀態
但是,Thread #1 發現要等硬碟將檔案狀態返回不知道要等多久,所以等的期間就不繼續執行 FS 的任務了,就讓 FS 任務等一下吧
所以這時 Thread #1 手上沒有任務了,PBKDF2 #4 的任務就被分配給 Thread 1# 執行了
最終 Thread #2, #3, #4 其中一個 Thread 會結束工作,我們假設 Thread #2 做完 PBKDF2 #1,就把 FS 的任務拿過來繼續做了,我記得我們剛剛講到 node 讀取檔案的步驟嗎?Node 會先 Request 要檔案的資訊,再發 Request 讀取檔案的內容,所以理論上 Thread #2 也會遇到一個將 Request 發給硬碟後的空窗期,但後面已經沒有任務了所以它就空著繼續等
這就是為什麼我們會在執行給果看到先 Hash 先完成,FS 會在後一個完成
驗收:那如果我們將 Hash 減少到兩個,結果會是如何呢?
現在每個任務都有一個 Thread 去執行了,FS 反而變最快了