无聊 + 新电脑 如何让 Rust 中的素数筛选器快了 64 倍(“Dopamine 优化”故事)

发布: (2026年2月16日 GMT+8 12:21)
4 分钟阅读
原文: Dev.to

Source: Dev.to

起源故事:它始于“一件新玩具”

大约六个月前,我坐在桌前,遭遇了严重的程序员创作瓶颈。我不想再去处理已有的 bug;我需要一次成功的快感——一次多巴胺的冲击。

恰好我正盯着一台对我而言全新的怪兽工作站:4.3 GHz i7、64 GB RAM、Quadro GPU。它是只野兽,我意识到我从未真正让它发挥过潜力。我想看到金属的光辉,想让风扇呼呼转动。

于是我给自己立了个挑战:用 C++ 写出绝对最快、最考验 CPU 的代码。数学运算量大,我于是选择了素数生成。找到了关于埃拉托斯特尼筛优化的论文,深入研究 SIMD 内在函数(AVX2/512),在一个疯狂的周末里纠结于缓存行和周期计数。最终我击败了标准库实现,看到 CPU 使用率飙到 100 %……但随即,多巴胺的快感也消散了。

“酷,下一步。”

我把代码搁置,忘记了它。

回忆闪回

快进到三天前。我在编译一个 Rust 项目,看到依赖一个接一个地滚动:

Compiling rand...
Compiling primes...

那一刻像砖头一样砸在我脑袋上。我手里有一整套高度优化、经受过实战考验的素数生成逻辑,静静地躺在一个尘封的 C++ 仓库里。我已经解决了最难的部分——位运算、缓存局部性、内存布局。

为什么我没有在 Rust 中使用它?

疯狂:移植到 Rust

害怕在实现之前把想法忘掉的冲动袭来。我进入了一个 12 小时的编码狂热状态。

目标不仅仅是移植,而是重新构想。在 C++ 中我直接玩指针;在 Rust 中我想要同样的性能,却拥有安全性和更好的易用性。

最终我得到了 Primer——一个 crate,具备以下特性:

  • 位压缩:每个奇数使用 1 bit(相当于每个数 0.5 bit)。
  • 仅奇数:硬编码 2,完全忽略偶数。
  • 内在函数驱动:使用 trailing_zeros(在 x86 上编译为 tzcnt)即时扫描筛子。
  • Kernighan 迭代:在硬件层面跳过零位。

结果:快 64 倍,体积小 95 倍

我没指望 Rust 编译器会这么配合,但结果让我大吃一惊。

基准测试 (n = 50,000,000)

  • 标准 Vec 实现:约 47 MB RAM
  • Primer(分段缓冲区):约 32 KB RAM
  • 速度:在批量生成时比 primes crate 快 64 倍

为什么这很重要(超越速度)

这个项目并不是因为需要素数而诞生的。它源于无聊和想看电脑“动起来”的欲望。

Prime sieve visualisation

有时候最好的代码并不是来自工单或需求文档,而是来自凌晨 2 点盯着闪烁光标时的自言自语:“我能让它更快吗…”,随后不经意间就造出了房间里最快的东西。

在 GitHub 上查看代码(以及基准测试):

👉

(另外,如果你是嵌入式 Rust 开发者——ESP32 / Raspberry Pi——这 32 KB 的占用正是为你准备的。尽情玩吧。)

0 浏览
Back to Blog

相关文章

阅读更多 »