iT邦幫忙

2021 iThome 鐵人賽

DAY 29
0
自我挑戰組

從C到JS的同步非同步探索系列 第 29

[Day 29] Node 非同步知識統整

前言

今天會統整這 10 多天關於 Node 框架的探索內容。

正文

  1. Node 的非同步, 本質是對 AIO 機制的活用, 其中 linux 使用的 AIO 機制是 epoll , windows 用的則是 IOCP。
  2. Node 可以粗略分成
    • JS 層 : 開發者撰寫程式的地方
    • C++層 : 負責連結 JS 層及 libuv 層
    • libuv 層 : 利用 AIO 機制完成 schedule 和 事件執行
  3. Node 的起點是 C++ 層, 他會在設定完基本環境後, 向上調用 V8 運行 JS 層, 向下調用 uv_run() 運行 libuv 層
  4. Node 在 JS 運行 IO 事件的本質是調用藉由 V8 分享的 C++ 層方法, 使用 IOCP / epoll 等方法註冊事件。所以平常 Node 運行一段具有 IO 功能的程式碼, 註冊完就會繼續往下一行運行了。
  5. uv_run 在 Node 創建之初就會開始運行, 其會不斷重複幾個階段 (以 IOCP 流程為主)
    1. libuv 開始循環
    2. timer stage : 檢查 time heap 中有沒有逾時的定時任務, 有就執行
    3. pending stage : 檢查 pending queue 中有沒有任務, 有就依照類別執行特定處理與 callback function
    4. polling stage : 利用 IOCP 抓取新發生的事件, 並且存入 pending queue
    5. endgame stage : pending 做完的事件會被推進 endgame queue , 在 endgame 階段關閉。
    6. 回到 timer stage
  6. time heap 是一個由 libuv 維護的最小樹, 需要定期觸發的任務會被註冊到這裡, timer stage 時取出結點, 藉由與當下時間比較有沒有逾時, 來決定要不要執行其 callback。
  7. IOCP 可以在發生已經註冊的事件後把事件存到 IOCP queue , 同時提供方法使 user space 取得 IOCP queue 中的事件。
  8. pending stage 處理抓到的事件時會根據不同的事件種類決定要做甚麼處理。
  9. Node 的 threadpool 沒任務時會閒置, 其目的是平行於 main thread 的完成 AIO 事件。
  10. 以下簡述 Node 中如何利用 thread pool 完成 AIO 事件 (以 IOCP 流程為主)
    1. C++ 層把 AIO 任務 (含 AIO 完成後的 callback) 放入 threadpool
    2. threadpool 完成 AIO 任務中 AIO 的部分 ( AIO 結束後的 callback 不在 TP 中執行)
    3. threadpool 觸發 AIO 完成的事件
    4. libuv 的 polling stage 抓取到 AIO 完成的事件後放入 pending queue
    5. libuv 的 pending stage 抓到 pending queue 中的 AIO 完成事件
    6. 執行基本的處理後調用該 AIO 完成事件所夾帶的 callback
    7. libuv 的 endgame stage 關閉執行完 callback 的 AIO 任務
  11. Node 以 libuv 來驅動 AIO , 藉以達成非同步框架。此外還配合, threadpool 來平行化部分流程。

明天進度

我明天會利用這段時間學到的知識實作一個可以運行少少幾句非同步方法的程式(乞丐版非同步架構),還有聊聊這 30 天的心得, 謝謝大家看到這裡

明天見 !


上一篇
[Day 28] Node thread pool 3
下一篇
[Day 30] 模仿 Node 的非同步實驗兼完賽心得
系列文
從C到JS的同步非同步探索30

尚未有邦友留言

立即登入留言