Go vs Nim 性能实测(一):6 项常规算法对决
系列导航 (一)6 项常规算法对决(本篇) (二)大数运算与 GMP 四端对比 (三)6 种 GC 模式全景对比
Nim 一直有个卖点:编译到 C、号称性能接近 C,写起来却像 Python。Go 以工程化著称,性能在同代语言里也不弱。两者到底差多少?网上各说各话,不如在自己机器上跑一遍。
这次对比一共五轮:常规算法、大数运算、GMP 四端 FFI、百万位 π 根因拆解、6 种 GC 模式。内容量比较大,拆成三篇发布。本篇是常规算法,同时是整个系列的方法学基础;第二篇讲大数与 GMP,第三篇讲内存管理。
本篇结论
一、测试环境与方法
| 项目 | 配置 |
|---|---|
| CPU / 系统 | Intel i9-11950H @ 2.60GHz(8C16T),Windows 10 企业版 LTSC |
| Go | 1.26.7,go build 默认优化 |
| Nim | 2.2.12(ORC),nim c -d:release --opt:speed --passC:-O3 --passL:-O3 |
| 采样 | 每项 7 次采样取中位数,单线程(Go 侧 GOMAXPROCS=1) |
方法学上只有一条硬规矩:每项负载两端必须输出一致的校验和。校验和统一定义为「bitlen × 10⁶ + 末 6 位」——只有两端算出的数完全一样,才能证明做的是同样的工作量,比出来的时间差才有意义。
后续两篇沿用同一套环境与采样方法,不再重复。
二、结果:6 项常规算法
6 项负载覆盖函数调用、整数运算、内存写入、随机访问、浮点与内存带宽,算法逻辑两端完全一致:
| 基准 | 负载特征 | Go (ms) | Nim (ms) | 谁更快 |
|---|---|---|---|---|
| fib32 | 递归函数调用 | 9.2 | 44.3 | Go,快约 3.8 倍 |
| sieve50M | 整数运算 + 内存写入 | 448.1 | 386.9 | Nim,快约 14% |
| quicksort2M | 随机访问 + 递归 | 154.2 | 165.9 | Go,快约 8% |
| matmul512 | 浮点运算(i-k-j 循环) | 122.6 | 97.7 | Nim,快约 20% |
| fnv64MB | 字节处理 / 内存带宽 | 93.0 | 57.9 | Nim,快约 38% |
| alloc2M | 小对象分配(GC vs ORC) | 22.6 | 66.9 | Go,快约 3 倍 |
| 合计 | 849.7 | 819.6 | Nim,快约 3.5% |
三、逐项拆解
fib32 —— 慢在递归(4.8×,全场单点差距最大)
Nim 默认 ORC 下函数调用与栈管理成本更高,Go 的栈增长式调用更便宜。这是典型的「调用密集型」负载,也是这一轮里差距最大的单项。
sieve50M / fnv64MB / matmul512 —— Nim 快 14%~38%
三项都属于「计算密集、无 GC 干扰」的类型,Nim 编译到 C 后能放开手脚优化。FNV 哈希尤其明显,几乎贴着内存带宽在跑。
quicksort2M —— Go 快 8%
随机访问 + 递归的混合负载,两端互有胜负,差距不大。
alloc2M —— 唯一体现 GC 差异的常规项
Go 的 GC 对小对象批量分配非常友好,快约 3 倍。第三篇会把这个差距放到更极端的场景里看,最高能到 38 倍。
四、怎么读这个结果
常规负载下两者确实打平,真正有价值的是分项结论:Go 的强项是函数调用与内存分配,Nim 的强项是把热点计算优化到贴近机器。写业务代码时,选型更应该看生态和团队熟悉度,而不是这 3.5% 的合计差。
但要提醒一句:「打平」只成立于常规负载。一旦进入大数运算、FFI 调用模式、GC 形态这些深水区,差距会拉开到数量级——那才是真正影响架构决策的部分。
五、复现
测试工程位于本机 benchmark/nimgolang(源码、脚本、CSV、可视化报告齐全):
脚本会自动:编译 → 各运行 N 次 → 校验两端校验和一致 → 取中位数 → 输出 CSV 与汇总表,并生成浏览器可直接打开的可视化报告(results/*_report.html)。
六、局限说明
- 单机单测:i9-11950H + Windows 10,其他平台与版本的结果可能不同。
- 单线程对比,未覆盖多核、并发与内存峰值。
- Nim 侧常规项默认使用 ORC;换成
--mm:refc等模式结果会变,第三篇给出了差异幅度。
下一篇:(二)大数运算与 GMP 四端对比——常规项打平,大数却是另一个世界:Go math/big 四项全胜,Nim 生态库最多落后 210 倍。