Rust、Golang、MoonBit 编译成 WASM,体积和速度差距有多大?

最近研究 WASM 性能的时候,做了一个不同编程语言的测试。

把同样的斐波那契算法,分别用 RustGolangMoonBit 写一遍,然后都编译成 WASM,看看谁的产物小、谁跑得快。

这次为了保证公平,三个语言统一使用 64 位整数进行对比。

结果测完发现,差距还是挺有代表性的。


为什么要测这个?

说实话,WASM 这几年越来越火了。

浏览器里跑高性能计算、边缘函数、Serverless、小程序插件,都离不开它。

但问题来了:选哪门语言写 WASM 更合适?

Rust 生态最成熟,Go 是后端老大哥,MoonBit 则是这两年专门为 WASM 和云原生设计的新语言。

我自己平时也在用 MoonBit,所以一直想知道:同样是编译到 WASM,它跟 RustGo 比起来到底处在什么位置?

这次就用一个最朴素的斐波那契算法,统一用 64 位整数实现,从产物体积和执行速度两个维度,做一个简单的横向评测。


测试环境

  • 机器:Intel i9-12900H
  • Node.js:v24.9.0
  • 测试工具:mitata
  • 语言版本:
    • Rust 1.96.1
    • Go 1.26.3
    • MoonBit 0.10.2

算法分递归版和迭代版,测试参数分别是 n=30n=35n=40

三个实现都编译成可在 Node.js 中加载运行的 WASM,在同一个 JS 宿主环境下被调用。


产物体积对比

先来看看到底编译出来多大。

语言 原始大小 gzip 后
MoonBit 211 B 178 B
Rust 286 B 235 B
Go 1.84 MB 565.78 KB

MoonBit 211 字节,Rust 286 字节,俩人都很小。

MoonBit 作为一个新语言,能把产物压到这个级别,说明它的编译器确实是为 WASM 专门优化过的。

Rust 也不差,286 字节同样是顶尖水准。

Go 则是 1.84 MB

原因大家都清楚,Go 的 WASM 产物要带一整个 runtime 进去,GC、调度器、协程这些东西一个都不少。

这是 Go 的设计选择,不是缺点,只是不太适合对体积敏感的场景。


性能对比

递归版斐波那契

n Rust MoonBit Go
30 5.74 ms 5.00 ms 14.24 ms
35 55.77 ms 50.03 ms 154.23 ms
40 667.43 ms 662.88 ms 1.70 s

递归场景下,MoonBitRust 非常接近,MoonBit 略快一点。

Go 慢一些,n=40 的时候大概是 MoonBit 的 2.5 倍左右。

这个结果并不意外,Go 在 WASM 下有 runtime 和 GC 开销,递归这种大量函数调用的场景本来就不是它的强项。

迭代版斐波那契

n Rust MoonBit Go
30 35.22 ns 14.70 ns 21.29 µs
35 38.52 ns 12.04 ns 18.33 µs
40 43.34 ns 12.29 ns 16.05 µs

迭代版的差距更明显。

MoonBit 是 12到15 纳秒级别,Rust 是 35到43 纳秒,Go 则是 16到21 微秒。

注意单位,Go 是微秒,其他两个是纳秒。

Go 慢这么多,不是说它的算法不行,而是 JS 调用 Go WASM 的运行时开销太大了。

每次调用都要经过 Go 的 JS 互操作层,参数转来转去,GC 还要插一脚,轻量任务根本吃不消。


我怎么看?

说实话,这次测试给了我三个挺深的印象。

第一个,MoonBit 在这个测试里表现不错。

产物最小,速度最快,而且它不是只编译到 WASM

WASMJavaScriptNative 三个后端都能输出,语法上有 GC、模式匹配、强类型系统,配套的 IDE 和包管理也还算完整。

从我实际使用的感受来看,如果你做的是边缘函数、Serverless、小程序插件这种对产物体积和冷启动敏感的场景,MoonBit 是一个可以考虑的选项。

当然,它的生态还在成长期,第三方库和社区规模跟 Rust 比还有差距。

第二个,Rust 依然是 WASM 的稳妥之选。

产物 286 字节,性能跟 MoonBit 在同一个量级,生态成熟度更是遥遥领先。

wasm-bindgenwasm-packwasm-opt 这些工具链已经非常完善了,遇到问题基本都能查到解决方案。

如果你要做长期维护、团队规模较大的项目,Rust 目前还是更稳的选择。

第三个,Go 标准编译器的 WASM 产物确实偏大。

但这是 Go 的设计取舍,它本来就是为了服务端、高并发、快速开发而设计的。

产物大是因为自带 runtime,调用开销高是因为 JS 和 Go runtime 之间需要频繁转换。

如果你已经有大量 Go 代码要复用,或者团队成员都是 Go 出身,那用标准 Go 编译 WASM 也能接受。

但如果从头选型,TinyGo 会是比标准 Go 更适合 WASM 的方案。


最后三句话总结

  • Rust 生态最成熟,文档最丰富。
  • MoonBit 产物更小、迭代性能更好。
  • Go 标准编译器不太适合对体积敏感的 WASM 场景。

不知道你怎么看呢?欢迎在评论区留言。

感谢阅读,我是前端之虎陈随易,公众号 陈随易,个人网站:https://chensuiyi.me

相关推荐
IT_陈寒1 小时前
Python多线程的坑,我居然现在才踩到
前端·人工智能·后端
魏祖潇2 小时前
DDD 完整指南——AI 时代工程师的第一道秩序分水岭
人工智能·后端
触底反弹2 小时前
🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
前端·javascript·算法
im_lanny2 小时前
如何给 Agent 打造“最强大脑“?深度解析短期记忆与长期记忆的分层设计
后端
Fanta丶2 小时前
2.Activiti表结构介绍 类关系
后端
触底反弹2 小时前
AI Tool Use 深度解析:大模型是如何"突破物理限制"调用外部工具的?
javascript·人工智能·后端
ClouGence2 小时前
SQL Server CDC 如何降低主库压力?Always On 备库读取实践
数据库·后端·sql·sqlserver
竹林8182 小时前
从 RPC 超时到批量签名:我用 @solana/web3.js 重构了一个 NFT 铸造页面,踩了这些坑
前端·javascript
工业HMI实战笔记3 小时前
工业HMI界面布局“1核2辅”黄金结构,适配90%场景
前端·ui·性能优化·自动化·交互