⭐⭐⭐⭐⭐ 5星

Rust WASM Parser重写为TypeScript反而快3倍

来源: Hacker News | 作者: OpenUI Engineering Team | 日期: 2026-03-13

摘要

OpenUI团队将Rust WASM解析器重写为TypeScript,性能提升2.2x-4.6x。核心发现:WASM边界开销才是真正的瓶颈,而非Rust代码本身的执行速度。

核心亮点

  • WASM边界税 - 字符串复制进/出、JSON序列化/反序列化开销远超Rust解析本身
  • serde-wasm-bindgen反而更慢30% - 试图跳过JSON往返反而因为跨边界细粒度转换更慢
  • 纯TypeScript方案 - 消除边界后,contact-form从61.4µs降到13.4µs (4.6x)
  • O(N²)流式问题 - 每个LLM chunk重新解析整个字符串,后来用增量算法解决
核心洞察: "Fewer, larger, and more optimized operations win over many small ones"

性能对比

测试用例 WASM (µs) TypeScript (µs) 加速比
simple-table 20.5 9.3 2.2x
contact-form 61.4 13.4 4.6x
dashboard 57.9 19.4 3.0x

问题分析

第一次尝试失败:使用serde-wasm-bindgen直接返回JS对象,反而比JSON方案慢30%。原因是JS无法直接读取Rust struct的字节,需要递归跨边界转换。

WASM边界开销

  • JS → WASM:字符串复制 + 内存分配 + memcpy
  • WASM → JS:序列化 + 字符串复制 + 内存分配 + memcpy
  • JSON.parse:V8 C++优化,处理效率高
解决方案:消除WASM边界,完全在V8中运行。JSON序列化在纯Rust中完成,单次memcpy,V8的JSON.parse是高度优化的C++代码。

流式解析优化

第二个问题是流式场景下的O(N²)复杂度:每个LLM chunk都重新解析整个累积字符串。

解决方案:语句级增量缓存

  • 以depth-0换行符结束的语句是不可变的
  • 缓存已完成语句的AST
  • 只重算尾部进行中的语句
  • O(total_length)复杂度替代O(N²)

教训

团队最初优化了错误的东西(Rust解析速度),而忽略了真正的瓶颈(边界开销)。这个案例提醒我们:

  • 先测量,再优化
  • 跨边界开销可能比预期大得多
  • V8的优化可能超出预期

相关资源

标签

性能优化 Rust TypeScript WASM V8