2个不稳定版本
0.2.0 | 2024年7月28日 |
---|---|
0.1.0 | 2024年7月22日 |
#13 在 #happy
每月下载量:278
在 iex 中使用
20KB
468 行
Rust的惯用异常
通过无缝使用异常进行错误传播,加快基于 Result
的函数“快乐路径”的速度。
快速入门
将 #[iex]
应用到所有返回 Result
的函数上,使其返回一个高效可传播的 #[iex] Result
,就像通常一样使用 ?
,偶尔需要真正的 Result
时调用 .into_result()
。这是非常直观的。
与代数 Result
相比,#[iex] Result
是非对称的:它牺牲了错误处理性能,作为回报
- 消除了快乐路径中的分支
- 通过从不显式存储错误或枚举区分符来减少内存使用
- 使编译器能够在将小对象包裹在
Ok
中时使用寄存器而不是内存 - 在机器码中清晰地分离快乐和不快乐路径,从而实现更好的指令局部性
基准测试
为了演示,我们将 serde 和 serde_json 进行了重写,以在反序列化路径中使用 #[iex]
,并使用 Rust JSON 基准测试 来比较性能。以下是结果
速度(MB/s) | 加拿大 |
citm_catalog |
twitter |
|||
---|---|---|---|---|---|---|
DOM | 结构体 | DOM | 结构体 | DOM | 结构体 | |
结果 |
296.2 | 439.0 | 392.4 | 876.8 | 274.8 | 536.4 |
#[iex] 结果 |
294.8 | 537.0 | 400.6 | 940.6 | 303.8 | 568.8 |
性能提升 | -0.5% | +22% | +2% | +7% | +11% | +6% |
数据是在5次运行中平均得出的。数据复制的存储库已发布在 GitHub 上。
示例
use iex::{iex, Outcome};
#[iex]
fn checked_divide(a: u32, b: u32) -> Result<u32, &'static str> {
if b == 0 {
// Actually raises a custom panic
Err("Cannot divide by zero")
} else {
// Actually returns a / b directly
Ok(a / b)
}
}
#[iex]
fn checked_divide_by_many_numbers(a: u32, bs: &[u32]) -> Result<Vec<u32>, &'static str> {
let mut results = Vec::new();
for &b in bs {
// Actually lets the panic bubble
results.push(checked_divide(a, b)?);
}
Ok(results)
}
fn main() {
// Actually catches the panic
let result = checked_divide_by_many_numbers(5, &[1, 2, 3, 0]).into_result();
assert_eq!(result, Err("Cannot divide by zero"));
}
依赖项
~0.6–1MB
~24K SLoC