Rust 视界
2.37K subscribers
461 photos
2 videos
17 files
5.09K links
Rust 热点、开源项目、动态
Download Telegram
ramhorns中的动态模板

#template_engine

ramhorns是一个实验性类Moustache的模板引擎。该作者(Pairtytech的工程师)写了这篇文章,主要记录他为ramhorns中动态模板提升性能的方案。

在Rust的世界里有很多模板引擎,可以分为静态模板和动态模板。

- 静态模板引擎,在编译时渲染。比如Askama。
- 动态模板引擎,需要在运行时进行渲染,比如Moustache,Handlebars和Zola(Rust实现的静态站点生成器)使用的Tera。

对于静态站点生成器,必须使用动态模板。而动态模板和Askama的性能存在5~30倍左右的差距。这让作者比较困惑,他在阅读了Askama和其他动态模板引擎的源码之后,发现Askama可以直接使用Rust类型渲染模板,而动态模板则需要一个中间结构表示,比如这种:

rust
#[derive(Serialize)]
struct Post<'a> {
title: &'a str,
content: &'a str,
}


然后通过序列化和HashMap这类数据结构在运行时获取相应的字段和值去渲染模板。这虽然有效,但是这种中间结构付出了沉重的代价。并且对于已经存在内存中的数据结构是完全冗余的。作者罗列了可能出现的开销:

- 如果要将字段名称和值转为字符串,则需要创建HashMap,这会双倍耗费堆内存。
- 如果有一个Vec或者是一些其他要展现的东西,比如帖子列表。将不得不创建一个新的Vec和多个HashMap。
- 每次对HashMap的插入和查找,都会有哈希处理带来的额外开销。

而静态模板引擎完全没有上述的开销。ramhorns如何优化?

> 使用宏来生成代码,并且使用比较字符串的hash值来代替直接比较字符串。使用了Fnv库。并且在模板预处理中使用相同的Hasher。

ramhorns中没有使用serde,而是使用了Content trait。利用宏,为Post结构生成如下代码:

r
ust
impl<'a> Content for Post<'a> {
fn render_field(&self, hash: u64, buf: &mut String) {
match hash {
// FNV-1a hash of "title"
0xda31296c0c1b6029 => buf.push_str(&self.title),

// FNV-1a hash of "content"
0x420c75b526b35282 => buf.push_str(&self.content),

// In Mustache fashion, do nothing if the field is not found
_ => {},
}
}
}

这样就避免了在运行时使用HashMap。优化的结果如何?作者和其他的模板引擎做了性能测试,发现ramhorns不仅比其他动态引擎更快,而且还比静态引擎Askama更快(其实Askama也有很大改进空间,Wearte项目就是案例)。作者说,也许再过一段时间,Hugo就不会说自己是「世界上最快的」静态网站生成器了。

- [Read More](https://maciej.codes/2019-03-03-ramhorns.html)
- [Wearte](https://github.com/dgriffen/wearte)
cuach: 又一个编译时模板

#template

[cuach](https://nest.pijul.com/pmeunier/cuach)