事件迴圈不是多執行緒:Node.js 併發最常見的誤會
Just a void 學海無涯
JavaScript 事件迴圈不是多執行緒:Node.js 併發最常見的誤會
Node 能同時處理幾萬個連線,常被誤解成多執行緒。它的併發其實靠單執行緒事件迴圈搭配非阻塞 I/O,runtime 主要只有一條執行緒在跑;讀檔、網路請求與資料庫查詢等待期間不佔用 CPU,loop 才能先處理其他事件,等 I/O 完成再回來繼續。這種「同時」是併發,並非真正的平行運算。
心智模型我通常這樣講:把 event loop 想成一個很快的服務生,在餐廳裡輪流招呼很多桌,每桌點完菜就去下一桌。問題出在哪?如果有一桌點了需要現炒 30 分鐘的菜,而且他站在那邊等,後面所有桌全都卡住。I/O 密集的場景(API gateway、WebSocket fan-out、proxy),服務生很少需要等,轉得飛快;CPU 密集的計算(影像處理、加密、遊戲伺服器即時運算),就是那道現炒,炒完之前誰都別想要菜。
worker_threads 確實可以把重 CPU 工作丟到另一條執行緒,但那不是不花成本的:序列化開銷、訊息傳遞延遲、記憶體隔離的限制,都是代價。這讓你得額外付出設計成本,即便 Node 依然能處理 CPU 工作。這也是為什麼有些後端我會選別的語言或 runtime:純粹是場景不對。一個需要即時物理運算的遊戲伺服器,選 Node 然後用 worker_threads 硬兜,不如一開始就用更適合的工具;一個以 I/O 為主、需要快速迭代的 API 服務,Node 幾乎沒有理由不用。
選型的本質是承認工具有邊界,然後選對場景,不是找「最強的」然後硬塞所有問題進去。
補充筆記
- Node.js 的高並發靠非阻塞 I/O 加事件迴圈,不是多執行緒,主執行緒始終只有一條。
- I/O 密集場景是最適場景,CPU 密集會直接把整條 event loop 堵住,影響所有連線。
worker_threads能補 CPU 工作,但不是零成本,序列化與訊息傳遞都有額外設計負擔。- 「能 build」不等於「場景合適」,選型前先確認工作負載的性質,再選工具。
- 事件迴圈心智模型:一個服務生、很多桌、一桌現炒、全場等。
觀點 Sheng,內文 Claude 協助 · 列入 20260613 blog 翻新計劃,新漆未乾。