真多執行緒!Bun 作者要給 JS 動大手術

![](https://p9-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/79b8fc3de967422eb24cee1230aab9eb~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5LqR5YmN56uv:q75.awebp?rk3s=f64ab15b&x-expires=1781770524&x-signature=iFMOSL%2Fjk3aKRCB3I7%2BRtGKcrdo%3D)

Bun 的創始人 Jarred Sumner 最近在社群平台上說了一句話:「我還是想要多執行緒 JavaScript。」

這不是他第一次提這個想法。早在 2024 年 5 月,他就發起過一個投票,問大家覺得共享記憶體的多執行緒 JS 和 AGI 哪個會先實現。結果 45% 的人選了多執行緒 JS,AGI 只拿到 32%,兩千多票,瀏覽量兩萬多。

這個數字很有意思。JS 多執行緒這個話題討論了快二十年,熱度一直不減,期待值甚至壓過了 AGI。

很多人可能會疑惑:Node.js 不是早就有 worker_threads 了嗎?瀏覽器也有 Web Worker,這還不夠嗎?

Jarred 的回覆很直接:「worker_threads 根本不是那回事。」

現在的 Worker 方案,本質上是多進程思路披了個多執行緒的外衣。每建立一個 Worker,底層會生成一個獨立的 V8 Isolate,有自己的堆記憶體、自己的垃圾回收器、自己的全域物件。

主執行緒和 Worker 執行緒之間完全隔離,想傳資料只能靠 postMessage。背後用的是結構化複製演算法,資料會被完整複製一份傳過去。傳一個 10MB 的物件,實際消耗 20MB 記憶體,還多了序列化和反序列化的開銷。

這帶來幾個現實問題:每個 Worker 在 Node.js 裡動輒消耗 30MB 以上,開 20 個 Worker,光執行緒本身就吃掉幾百 MB;通訊成本高,頻繁通訊的場景下效能損耗明顯;狀態無法共享,兩個執行緒不能直接操作同一個物件。

這哪是多執行緒,更像兩個獨立的 JS 行程在靠訊息佇列通訊。

Jarred 想要的是什麼樣的?

他給出了具體描述:一個全域物件,所有執行緒共用同一個堆,一個垃圾回收器統一管理記憶體,物件可跨執行緒存取。執行緒 A 建立的物件,執行緒 B 可以直接讀寫,不需要複製。

沒有 postMessage 開銷,執行緒間通訊不用序列化,直接操作共享記憶體裡的物件,單執行緒記憶體占用小於 2MB,可以輕量地開大量執行緒。

這基本上就是 Java、Go、C++ 的執行緒模型。在這些語言裡,多個執行緒天然共享同一塊堆記憶體,直接把物件參考傳給另一個執行緒,對方立刻就能操作,沒有任何複製。

從效能角度看,這才叫多執行緒。

既然好處這麼明顯,為什麼 JS 一直做不到?

答案藏在 V8 引擎的設計裡。V8 用 Isolate 作為獨立執行單元,每個 Isolate 擁有自己的堆和 GC,彼此完全隔離。

這個設計的初衷是安全和簡單。單執行緒模型下不需要考慮並發存取衝突,GC 可以在沒有外部干擾的情況下自由回收記憶體。

要打破這個邊界,最大的障礙是記憶體安全。多執行緒共享記憶體最頭痛的是競態條件,兩個執行緒同時修改同一個物件,可能導致資料損壞甚至程式崩潰。

Rust 用所有權模型在編譯期杜絕了這類問題,但 JavaScript 是動態語言,沒有型別系統保障,靜態檢查很難做。

另一個難點是 GC。傳統 GC 假設自己獨佔堆記憶體,標記物件時不希望別的執行緒在旁邊改動。多執行緒共享堆之後,GC 要麼頻繁暫停所有執行緒,要麼實作複雜的並發 GC,工程難度都不小。

這就是為什麼 SharedArrayBuffer 是目前 JS 標準裡最接近真正共享記憶體的東西,但它只能存原始位元組,不能存物件,限制很大。

Node.js 受制於 V8 的 Isolate 架構,想改執行緒模型得跟 V8 團隊一起動,牽一髮而動全身。

Bun 不一樣,它從底層重新實作了 JavaScript 執行環境,用的是 JavaScriptCore 而不是 V8。Bun 對自己執行環境架構的控制權,比 Node.js 大得多。

這意味著 Bun 有能力在不觸動 V8 的情況下,去實驗一種新的執行緒模型。

TC39 有個叫 Shared Structs 的提案正在推進,允許定義可在多個 JS 執行緒之間共享的結構體,配合 Mutex 和 Condition 來解決並發存取問題。但這個方案離 Jarred 描述的「普通 JS 物件隨意跨執行緒共享」還有距離。

如果有一天 JS 真的實現了共享多執行緒,Node.js 的程式設計模型會發生根本變化。影像處理、加密運算、資料解析這類 CPU 密集型工作,都能用純 JS 執行緒高效平行處理。

更直接的影響是記憶體效率。10 個 Worker 現在要多用幾百 MB 記憶體,真正的共享執行緒模型下,同樣 10 個執行緒的額外開銷可能只有 20MB 不到。

JavaScript 的單執行緒模型,幫它避開了幾十年的並發地雷,代價是在 CPU 密集型場景上始終留著一塊短板。

Jarred 的願望不是第一次說,但這次背後多了 Bun 這幾年累積的工程實力,以及他對執行環境底層的掌控權。

JS 的多執行緒時代,也許真的比我們想像的要近一些。你怎麼看?歡迎留言區聊聊。


原文出處:https://juejin.cn/post/7649936611648700454


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
362
🥈
我愛JS
💬1  
3
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
📢 贊助商廣告 · 我要刊登