克雷西 發自 凹非寺
量子位 | 公眾號 QbitAI
30周年之際,Ruby語言帶著全新的4.0版本,給開發者送上了年終大禮。
增隔離命名空間新的JIT編譯器,還有重設計的Ractor API,這款開源語言迎來一系列更新。
![]()
Ruby是一種開源的面向對象腳本語言,在20世紀90年代由日本人松本行弘開發,遵守GPL協議和Ruby License。
其主要特性就是簡單快捷,變量沒有類型、任何東西都有值,不需要注釋就可以讀懂。
對于這次更新,網友們給予了高度評價,表示要是沒有Ruby更新,連圣誕節都不完整了。
![]()
那么,30歲的Ruby,這次都迎來了哪些更新呢?
全新編譯器ZJIT
Ruby 4.0中,Rails at Scale團隊正式推出了名為ZJIT的全新即時編譯器(Just-In-Time Compiler)。
這是一種一種傳統的方法級編譯器,核心架構采用了靜態單賦值(SSA,Static Single Assignment)形式的中間表示,旨在突破現有YJIT編譯器的性能上限。
傳統的Ruby解釋器是逐行執行代碼,效率較低,而JIT編譯器則是將熱點代碼轉換成機器碼。
其中,YJIT的設計理念聚焦于局部,它將編譯視域限制在微小的基本塊(Basic Block)中。
這種策略雖然能快速生成機器碼并降低內存占用,但由于缺乏對代碼整體結構的認知,難以進行跨越整個方法的全局優化。
相對而言,ZJIT引入了SSA中間表示技術。在這種架構下,編譯器會分析完整的方法體并構建全局數據流圖,確保每個變量在邏輯上僅被賦值一次。
這種全局分析能力賦予了ZJIT執行常量折疊(在編譯期直接計算固定結果)和死代碼消除(移除無效計算步驟)等深度優化的潛力,這些都是YJIT受限于架構而難以高效實現的。
在處理Ruby的動態類型特性時,兩者也采用了截然不同的路徑。
YJIT傾向于通過版本化機制保留多條代碼路徑以適應不同的變量類型。
ZJIT則采用了側向退出(Side-exits)機制。
它會基于當前類型穩定的假設生成單一且激進優化的機器碼,一旦運行時檢測到變量類型不再符合預期(例如整數變為字符串),程序會立即觸發側向退出,終止當前優化代碼的執行并安全回退到解釋器。
![]()
這種機制允許編譯器在假設成立的前提下剝離大量冗余檢查。
盡管ZJIT目前的綜合性能尚未完全超越成熟的YJIT,但其基于SSA的嚴謹架構可以突破局部優化帶來的瓶頸,為Ruby在未來實現更復雜的代碼分析和更高的峰值性能奠定了基礎。
![]()
隔離命名空間Ruby::Box
Ruby::Box是一個專門用于隔離代碼執行環境的容器類,目的是解決長期困擾Ruby開發者的“全局污染”問題,并為構建更安全、模塊化的應用提供原生支持。
這涉及到Ruby的一個核心特性——開放類(Open Class)。
在傳統的Ruby環境中,任何代碼都可以隨時修改系統內置的類(例如給String類添加新方法),這種行為被稱為“猴子補丁”(Monkey Patching)。
雖然這種特性賦予了語言極大的靈活性,但在大型項目中,如果不同的第三方庫同時修改了同一個類,就會引發嚴重的命名沖突。
Ruby::Box通過徹底的命名空間隔離(Namespace Isolation)解決了這一難題。
![]()
當代碼在某個Box中運行時,它對內置類的修改、定義的全局變量或頂層常量,都被嚴格限制在當前Box的內部作用域中,完全不會“泄漏”到外部環境或其他Box中。
從架構設計的角度來看,Ruby::Box被定義為Module的子類,這意味著它本質上也是一種模塊。
在Ruby4.0的運行模型中,所有的用戶主程序默認運行在名為“main”的Box中。而當開發者通過Ruby::Box.new創建新的隔離環境時,系統會基于包含最原始、純凈Ruby環境的“root”Box進行復制。
為了確保高性能,這一過程采用了寫時復制(Copy-on-Write)技術,這使得創建新Box的內存開銷極低,同時保證了各個環境之間的獨立性。
此外,Ruby::Box還提供了文件級的作用域控制能力。通常情況下,一個.rb文件的加載和執行可以被限定在一個單一的Box中,這意味著該文件內的所有方法定義和常量解析都在該Box的上下文中完成。
這對于開發插件系統、多租戶應用或者需要運行不可信代碼(沙箱環境)的場景具有革命性意義。它允許開發者在保留Ruby動態特性的前提下,構建出更加健壯、安全且易于維護的系統架構。
重設計的Ractor API
在Ruby4.0的更新中,為了解決Ruby3.x時代Ractor通信中存在的“多路通信混亂”和“消息竊取”等諸多痛點,Ractor API也迎來了一次重大的重構。
其核心在于引入了Ractor::Port機制,讓并行編程變得更加直觀和安全。
在早期版本中,Ractor主要依賴“推”(Push)和“拉”(Pull)兩種模式。當多個Ractor向同一個目標發送消息時,接收方往往難以分辨消息的來源,就像所有信件都被塞進了一個沒有標簽的公共郵箱。
而在新版設計中,Ractor::Port充當了專用信道的角色,任何人都可以向這個端口發送消息,但只有端口的創建者才有權從里面取出消息。這種“多對一”的單向通道設計,完美契合了Actor模型的語義。
![]()
具體的改進主要體現在三個方面:
首先是消息的定向投遞與安全性。通過Ractor::Port,消息不再是廣播式的混亂投遞,而是精準地發送到指定的端口。這徹底杜絕了“消息竊取”現象,即A模塊發送的消息意外被B模塊的接收函數截獲。
其次是摒棄了復雜的同步原語。新版本廢棄了Ractor.yield和Ractor#take等容易引發死鎖和競爭條件的舊方法,轉而使用更清晰的Ractor#send配合端口機制。
同時,為了處理Ractor的生命周期,引入了與線程類似的Ractor#join(等待結束)和Ractor#value(獲取返回值)方法。
特別是Ractor#value,它設計為只能被一個Ractor調用一次,這種限制允許系統在不復制對象的情況下安全地傳遞返回值,極大地提升了效率。
最后是高效的多路復用。新的Ractor.select方法經過重寫,現在支持同時監聽多個Ractor::Port。
當任何一個端口收到消息時,select會立即返回該端口和對應的消息。這比傳統的輪詢機制要高效得多,并且解決了過去在復雜并發場景下難以協調多個數據源的問題。
總的來說,Ractor::Port的引入通過更輕量級的實現和更嚴謹的通信契約,為Ruby開發者提供了一套既符合直覺又具備高性能的并發工具箱。
其他更新
除了上面三個比較大的方面,這次Ruby 4.0還有一系列其他更新:
- 語法更符合直覺:邏輯運算符現在可以寫在換行后的行首,不再強制要求放在上一行行末;
- 核心庫“轉正”:Set和Pathname從標準庫升級為核心庫,開發者無需再手動編寫require語句;
- 調試體驗升級:當發生參數傳遞錯誤時,ErrorHighlight功能現在不僅會高亮顯示“調用出錯”的代碼行,還會同時顯示“方法定義”的代碼行,方便開發者快速對照排查;
- 緊跟Unicode標準:完整支持Unicode17.0標準,能原生識別和處理最新的Emoji17.0表情符號;
- 更嚴格的空值檢查:為了防止空值意外轉換成空數組從而掩蓋代碼邏輯中的Bug,nil對象不再響應to_a方法;
- 性能底層優化:Class.new(創建新類)的速度在所有場景下都得到了顯著提升;垃圾回收機制(GC)現在能獨立管理不同大小的內存池,有效降低了內存占用;
- 更靈活的數組查詢:Array類新增了rfind方法,可以高效地從數組末尾開始向前查找符合條件的元素;
- 自定義對象展示:Kernel#inspect方法新增了定制功能,開發者可以通過定義instance_variables_to_inspect來決定在打印對象調試信息時顯示哪些變量,避免輸出過多無關信息。
那么,你覺得更新后的Ruby,有沒有更好用呢?
[1]https://www.ruby-lang.org/en/news/2025/12/25/ruby-4-0-0-released/
[2]https://docs.ruby-lang.org/en/master/Ruby/Box.html
[3]https://railsatscale.com/2025-12-24-launch-zjit/
[4]https://dev.to/ko1/ractorport-revamping-the-ractor-api-98
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.