likes
comments
collection
share

用 Rust 写了个 Node.js 拓展速度提升了 100%?

作者站长头像
站长
· 阅读数 13

前言

先贴一组我使用 Rust 和 TypeScript 写的相同功能的工具的性能对比,这个包的作用是将 JsonSchema 转换为 TypeScript 类型,它们的代码逻辑是完全一样的,最后得到的结果是性能提升了接近 100%(用的笔记本 10 代 i7 跑的),当然换 C++ 或者 C 语言来写 Native Addon 可能也差不多是这个结果,但是我更熟悉 Rust 一些,所以就用 Rust 来搞了~, 这篇文章主要来讲讲我用 Rust 开发 Node.js 工具时的感受。

Task Nameops/secAverage Time (ns)MarginSamples
TypeScript: schema2ts2,796357534.31021794415±1.08%1399
Rust: rustySchema2ts5,431184122.05448994122±0.29%2716

跑了几次结果都在这个区间上下浮动,然后就得出了提升 100% 这个结论~,感兴趣的同学可以去看下 @puffmeow/rusty-schema2ts 这个包。

开发时的感受

用 Windows 系统开发蛋疼

不得不说,用 Windows 系统开发心态就是很搞,很多 Unix 的命令都不支持(虽然可以在虚拟机里跑,但体验也不爽),有条件的还是整一个 Mac 来开发会舒服很多。还有 Windows 的换行符默认用的 CRLF 就很蛋疼,在 Unix 系统上都是 LF,这会导致跑单测的时候会出现报错,明明单测对比结果完全一致但就是不通过,就是因为这个换行符导致的。

写代码时感觉还行

用 Rust 写代码肯定就要考验语法的基本功了,当时我是先写好了 TypeScript 版本的,然后就萌生了想法想看看 Rust 来完全翻译过来速度会有多大提升,最后测试完成后就得到了这篇文章的结论,提升了 100% 这样。写这个工具的时候核心逻辑全部用的 Rust,然后测试用的 Vitest 框架,整体开发下来感受还行,只要熟悉 Rust ,开发时基本没遇到啥太大的问题,也没遇见 Rust 所有权、生命周期这些难啃的骨头,也可能是我这个场景太简单了哈哈~,不过如果遇到所有权问题的时候,套一下 Rc 或者 Arc 也能很快解决,问题不大。

跨平台很麻烦

首先是跨平台这个问题,Native Addon 是不支持跨平台的,在每个平台上只能编译出自己对应平台的 node 文件,如果你想要这个包能够分发给全平台的机器用,就需要在这些不同平台的容器/虚拟机中进行构建, napi-rs 提供了很便捷的跨平台构建工具,有了这个工具后我们还需要依赖 Github workflow,通过流水线在不同平台的容器构建好,最后在云端进行发布 NPM 包。这整个构建的流程如下图,我这个工具核心代码 800 行左右,每次发布都需要差不多 10 分钟,这其中包括了构建和跑测试用例的过程。想要改点东西时重新发包就要等很久~ 而且要构建的时候十分依赖于 Github,很多公司里面都没集成这样的跨平台构建流水线(阿里集团内部目前也没看到有,倒是蚂蚁是有的)

用 Rust 写了个 Node.js 拓展速度提升了 100%?

总结

掌握了使用 Rust 编写 Node.js 工具后,以后一些吃 CPU 计算的工具都可以用 Rust 来写给 Node.js 调用了~ 特别是读写文件,Swc/Rspack/Farm/Rome 这些我们之前提到的前端工具都是读写文件类型的,所以它们宣传性能提高了 xx 倍也很合理。首先是因为 Rust 性能本身就好,其次是因为架构设计得合理,最后才有了性能提高 xx 倍的结果。如果使用 Node.js 写服务端,那其实就不需要考虑上面的跨平台构建了,把 Rust 代码在本地写好之后,最后到服务器上构建的时候只需要构建当前服务器这个平台即可。但是可能有人会问,为什么不直接就用 Rust 来写服务端了呢,还要搞这么麻烦? 原因是 Node.js 开发效率比较高,而且只有在遇见吃性能场景的时候我们才会去使用 Rust,大部分场景其实都是 IO 密集型场景,也没太大必要,当然你也可以单独起一个 Rust 微服务,但是这时候就会多一层网络开销,网络传输大概是没有本地调用的速度快的。就这么个回事。

最后,Rust 这玩意感兴趣就学,不感兴趣看看就好,大部分开发的场景中我们是遇不见 CPU 密集型场景的,但是一旦遇到的时候,我们就要能够有对应的解决手段,这就是我们的能力。

这篇文章同时收录在公众号《泡芙玩编程》,公众号主打前端、Node.js、Rust,欢迎来玩~