service phone

400-123-4657

NEWS 易倍动态

service phone 400-123-4657

emc易倍 | 行业资讯 |

EMC易倍我用 Rust 重写网站性能居然提升了 18 倍!

点击量:931    时间:2022-09-06

  我使用Hakyll编写我的静态网站已经有9年了。在此之前,我使用过Jekyll,还使用过Perl的Mojolicious和PHP的Kohana编写更动态的页面。

  在我的笔记本电脑上,重构一次网站需要75秒(不是编译,只是生成网站)。我的网站只有240个帖子,所以我认为不至于如此之慢。虽然我可以使用缓存系统,并在编辑期间通过watch命令查看更新后的帖子,但这个速度仍然是我无法接受的。

  虽然站点生成器本身是用Haskell编写的,但除了许多Haskell库之外,还有一些依赖项。我的博客助手脚本是用Perl编写的,我使用sassc转换sass,然后利用Python的pygments高亮显示语法,并使用s3cmd将生成的站点上传到S3。

  安装所有这些工具并保持最新状态是一件很麻烦的事情。我希望能有一个统一的工具解决所有问题。

  有时,网站会出现一些问题,我必须花时间调试和修复。每当我有一些新的写作思路,却发现网站生成器有问题,就会觉得很沮丧。

  如果Hakyll升级时会修改Pandoc参数,那么就会破坏Atom feed中渲染的代码。

  我很喜欢Haskell,尤其是纯函数的部分,而且我非常喜欢Hakyll通过声明式的方法处理站点配置。以生成静态页面(即单独的页面)为例:

  但是我已经很多年没有使用过Haskell了易倍动态,而且我不想在网站上添加复杂的东西。

  例如,我曾想在帖子中添加链接“下一个/上一个”,但后来我不得不花时间重新学习Haskell和Hakyll。即便如此,最后我想到的解决方案还是超级慢,因为我采用了一个线性搜索来查找下一个/上一个帖子,但我未能搞清楚如何正确地利用Hakyll实现这个链接。

  我想编写一个静态站点生成器,这是一个非常有趣的项目,难度应该不大,但可以让我全权控制网站,而且灵活性完胜我使用过的所有网站生成器。

  起初我很担心重新实现我喜欢的Hakyll功能的难度会太大,例如模板引擎、多种语言的语法高亮显示,以及通过watch命令自动重新生成编辑过的页面并充当文件服务器,这样我就可以在写作的过程中随时在浏览器中查看帖子。

  事实证明,我可以利用现有的库处理一些难度较大的工作。以下是我使用的一些效果很好的库:

  scraper:解析生成的HTML。我的一些测试和特定的转换中用到了这个库。

  即便使用了这些库,Rust源代码本身也超过了6000行。在有些情况下,Rust代码可能会很冗长,我的代码确实不够漂亮,但是最后的代码量仍然超过了预期。

  如果我的帖子都采用标准的markdown,这个转换过程会更加容易,但多年来我添加了很多pulldown-cmark不支持的功能和扩展。所以,我不得不自己编写代码。

  我有一个预处理步骤,利用多个图像来生成插图。这是一个通用的处理步骤,形式如下:

  我使用这个预处理来生成各种图像集合,例如Flex、Figure和Gallery。下面是一个例子:

  以前我喜欢降低标题等级,并嵌入原始YouTube链接,而且实现起来很简单(不过,在处理前后的步骤中嵌入YouTube链接可能会更好)。

  我在Pandoc中使用的功能还有一个不受支持:在HTML标签内计算markdown。比如下面这段代码就无法正确呈现:

  起初我的计划是,在通用预处理中实现,但后来发现这样做会丢失链接引用。比如下面这个例子:

  虽然现有的crate使用syntect高亮显示代码,但我自己编写了一个crate,可以将它包装在标记中,并支持内联代码高亮显示。例如:

  我没有在提高性能上花费太多时间,但以下两方面的改动对性能产生了很大影响:

  第一,如果使用syntect,并且使用自定义的语法,则应该将SyntaxSet压缩为二进制格式。

  EMC易倍

  第二,使用rayon并行化渲染。渲染是解析Markdown、应用模板以及创建输出文件的过程。rayon非常适合该任务,因为这项任务的瓶颈是CPU,而且rayon非常易于使用(如果代码结构正确)。例如,下面是一个简化的渲染:

  如果想并行化上述处理,我们只需要将iter()改为par_iter():

  诚然,性能上的提升非常小,几处巨大的性能提升都来自我使用的库。例如,我的旧网站使用了一个用Python编写的外部pygments来高亮显示语法,而现在我使用了Rust的高亮显示EMC易倍,它的速度要快得多,并且很容易并行化。

  以前,我的网站给我的最大困扰是,太容易出错了。例如,链接到不存在的页面或图像,忘记定义链接引用,或者忘记在发布之前更新链接。

  因此,除了测试watch命令之类的基本功能之外,我还需要解析整个站点,并检查所有内部链接是否存在以及是否正确。此外,我还需要手动检查外部链接。

  如今在我的笔记本电脑上,重建完整的站点需要4秒(不包括编译时间)。18倍的性能提升看起来不错嘛。我相信,网站的性能还有进一步提升的空间,例如使用rayon处理文件I/O,使用异步处理,而且我没有缓存系统,所以每次构建都会重新生成所有文件。

  请注意,这并不是说Rust的速度远超Haskell,这不过是两种实现的比较。我相信有人能够使用Haskell编写出更快的实现。

  只要系统安装了Rust,cargo build就可以正常工作。我认为这是Rust最大的优势之一:构建系统可以正常工作。

  你不必手动寻找丢失的依赖项,为了实现跨平台而苦恼,或者在构建系统自动拉取更新时破坏一切。你只需要静静等待代码编译完成。

  虽然我找到了更简单的方法来实现上一个/下一个链接,但我并不认为这意味着Rust比Haskell更简单或更容易,这只是意味着Rust对我个人来说更容易理解。

  最大的原因还是要归结为实践。最近我一直在使用Rust,但对于Haskell,我只在大约十年前构建这个网站时学习过一段时间,之后再也没有接触过。

  总的来说,我很满意这次重写网站的结果。这是一个有趣的项目,尽管工作量超出了我的预期EMC易倍,但的确解决了我的一些烦恼。

地址:广东省广州市天河区88号     座机:400-123-4657    手机:13800000000
Copyright © 2018-2023 emc易倍·(中国)移动端下载 版权所有  xml地图  网站地图  备案号:桂ICP备2021003322号-1