Rust 已把 Python 套件加速,為何還要用 C 重寫一次?關鍵不在語言勝負,而在產品邊界:前者優化 Python 使用者既有的呼叫路徑,後者則移除 Python 執行環境,將 JSON 解析、XML 序列化、命令列介面與可嵌入函式庫收進更小的原生工具。這也是這次重寫真正值得討論之處。
事件背景:不是替換 Rust,而是另做一種產品
來源事實:json2xml 原本是 Python 套件,後來加入以 PyO3 製作的 Rust 擴充,在不改變 Python API 的前提下加速常用轉換流程。官方文件也將它定位為可選的原生後端,供需要 Python 介面與更高速度的使用者採用:https://json2xml.readthedocs.io/en/latest/readme.html。
新推出的 json2xml-c 則直接接收 JSON 位元組,自行解析成資料樹,再輸出 XML;同時提供 C23 API 與獨立命令列程式。作者明確表示,它不是另一個 Python 後端,也不是要證明 C 優於 Rust,而是面向不需要 Python、希望單一執行檔或要把轉換器嵌入既有 C 系統的情境。原始說明與測試數據見:https://vinitkumar.me/json2xml-c/。
速度從哪裡來:縮短整條資料路徑
來源事實:作者的基準測試比較三條路徑:C 版從記憶體中的 JSON 位元組完成解析與序列化;Python/Rust 路徑先執行 json.loads,再把 Python 物件交給 Rust;第三組則排除 JSON 解析,只測已解析物件進入 Rust 序列化器的時間。PyO3 官方文件確認,其用途正是建立 Rust 實作的 Python 原生模組,因此 Python 物件與擴充模組之間的介面確實屬於產品路徑的一部分:https://pyo3.rs/main/index.html。
在作者公布的 Apple Silicon 測試中,42 位元組輸入的完整 C 流程為 511 奈秒,Python/Rust 完整流程為 2.76 微秒;輸入增至 295,134 位元組時,兩者分別為 2.94 與 4.45 毫秒。四組資料顯示,C 版端到端快 1.51 倍至 5.39 倍。測試在計時前先確認輸出逐位元組一致,結果取 21 次樣本的中位數,並排除檔案讀取、測資產生與程序啟動。
合理推論:小型輸入的差距最大,顯示固定成本——Python 函式呼叫、物件處理與跨語言邊界——可能比實際轉換工作更顯著;資料變大後,解析與序列化本身占比上升,差距便收斂到約 1.5 倍。這支持「較短的完整堆疊比較快」,卻不能推出「C 的核心演算法必然比 Rust 快」。
商業與部署邏輯:少一個執行環境,就是一種價值
作者聲稱首版提供 Linux、macOS、Windows 的 x86-64 與 ARM64 壓縮檔,Linux 執行檔採靜態連結,並附 SHA-256 校驗碼。工具不內嵌 Python,也不使用第三方 JSON 解析器;它甚至刻意不支援從 URL 抓資料,因為 HTTPS 會帶入 TLS 相依性。
作者觀點:這類「少做一些事」不是功能不足,而是部署策略。單一用途工具若能被放入容器、韌體建置流程、資料轉換管線或離線環境,安裝與更新面積可能比每次轉換省下多少微秒更重要。反過來說,若團隊本來就全面使用 Python,移除執行環境並不會自動產生效益,反而要多維護另一套介面與發布流程。
容易忽略的限制:漂亮數字不等於普遍結論
- 測試只來自一台 Apple Silicon 機器、四組產生的測資與精簡 XML 輸出,尚未涵蓋多種 CPU、編譯器、作業系統及真實世界資料分布。
- 程序啟動、檔案 I/O 與測資生成不在計時範圍;因此結果不能直接代表大量短命 CLI 呼叫的實際延遲。
- 文章沒有提供跨平台效能、尖峰記憶體、執行檔大小或長時間模糊測試結果,部署優勢仍缺少完整量化。
- 相容性、配置失敗注入、ASan、UBSan、函式與行數 100% 覆蓋率,均是作者公開的品質證據;但分支覆蓋率為 82.10%,且本文未獨立重跑測試,不能把它們等同於沒有缺陷。
C 的代價尤其不能被效能數字遮蔽。OpenSSF 將 Rust 列為「預設記憶體安全」、C 與 C++ 列為「預設不具記憶體安全」,並強調後者必須持續依靠工程規範與自動化工具降低風險:https://memorysafety.openssf.org/memory-safety-continuum/。json2xml-c 採用配置失敗測試與 sanitizers,方向符合這項建議,但工具只能提高發現錯誤的機率,不能提供 Rust 型別系統的編譯期保證。
對台灣團隊的意義
對製造、邊緣運算、設備整合及受限網路環境常見的台灣開發場景,這個案例提供一個實用決策框架:先問交付物要嵌入哪個系統、允許哪些執行環境、誰負責安全更新,再談語言速度。需要 Python API 與既有套件相容性時,Rust 擴充仍是合理選擇;需要可攜的獨立 CLI 或 C ABI 時,完整原生管線才可能值得承擔額外的記憶體安全責任。
更廣泛的啟示是:原生擴充不一定要無限優化同一個函式。當跨語言物件、封裝與執行環境成為主要成本,重新畫定產品邊界,有時比更換演算法更有效;但重寫的效益必須連同維護人力、弱點回應與多平台測試一起計算。
後續觀察指標
- 是否出現第三方可重現的跨平台 benchmark,以及真實、深層巢狀或 Unicode 密集資料測試。
- 模糊測試、記憶體用量、執行檔大小與啟動時間是否被納入公開報告。
- C 版與 Python/Rust 版能否持續維持逐位元組相容,並同步修補安全問題。
- 實際採用者究竟把它當 CLI、共享函式庫或嵌入式元件;這將決定重寫是否真的創造了 Rust 擴充無法服務的市場。