Rust循环POC运行极慢原因排查:对比Go性能疑问
嘿,作为Rust新手能写出POC已经很棒了!咱们来一步步拆解你的代码里拖慢性能的问题,让它发挥出Rust应有的速度:
核心性能问题分析
你的代码慢的主要原因集中在这几点:
1. 夸张到离谱的循环次数
最外层的for _i in 0..1000000000是10亿次循环!哪怕每次循环只做极简单的操作,10亿次也会消耗巨量时间——这绝对是最大的性能杀手。你是不是笔误把测试次数写错了?比如本来想写1000次而非10亿次?Go版本能几秒完成,大概率是没有这么夸张的循环次数。
2. 动态Value的频繁无类型访问开销
serde_json::Value是动态类型的JSON表示,每次访问data["tl"][i]["t"]这类路径时,都会做:
- 哈希表查找(因为
Value的对象是哈希表结构) - 运行时类型断言(比如
as_array().unwrap())
这些操作在循环里重复执行,累积起来的开销非常大。而Go如果用结构体解析JSON,是静态类型访问,没有这些运行时开销。
3. 不必要的重复计算
你每次内层循环都重复调用data["tl"].as_array().unwrap().len()、data["el"].as_array().unwrap().len()——这些值在整个rule函数执行过程中是完全不变的,却被重复计算了无数次。
4. 字符串比较的额外开销
data["tl"][i]["t"] == "my_value"这类比较,需要先把Value转换成字符串再做对比;如果用静态结构体,直接是字符串切片的比较,效率高得多。
优化后的代码示例
我们用静态类型结构体代替动态Value,提前提取不变值,修正循环次数,再加上一些Rust风格的优化:
首先确保Cargo.toml里的依赖正确:
[dependencies] serde = { version = "1.0", features = ["derive"] } serde_json = "1.0"
优化后的代码:
use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fs::File; use std::io::BufReader; // 定义与JSON结构匹配的静态类型结构体 #[derive(Debug, Deserialize, Serialize)] #[serde(borrow)] // 直接借用JSON中的字符串,避免不必要的克隆 struct TlEntry<'a> { t: &'a str, refu: &'a str, eu: &'a str, } #[derive(Debug, Deserialize, Serialize)] #[serde(borrow)] struct ElEntry<'a> { is_inpatient: bool, eu: &'a str, } #[derive(Debug, Deserialize, Serialize)] #[serde(borrow)] struct Data<'a> { tl: Vec<TlEntry<'a>>, el: Vec<ElEntry<'a>>, } fn rule(data: &Data) { let ru = "589ea4b8-99d1-8d05-9358-4c172c10685b"; // 提前构建el的索引:用eu作为key,快速匹配 let mut el_index = HashMap::new(); for el_entry in &data.el { if el_entry.is_inpatient { el_index.entry(el_entry.eu).or_insert_with(Vec::new).push(el_entry); } } // 假设这里是笔误,改成1000次测试循环(你可以根据需求调整) for _i in 0..1000 { for tl_entry in &data.tl { if tl_entry.t == "my_value" && tl_entry.refu == ru { // 直接通过索引查找,无需遍历整个el数组 if let Some(matching_entries) = el_index.get(tl_entry.eu) { for _entry in matching_entries { // 这里放你的业务逻辑 } } } } } } fn start() -> Result<(), Box<dyn std::error::Error>> { let file = File::open("../../data.json")?; let reader = BufReader::new(file); // 解析为静态类型Data,而非动态Value let data: Data = serde_json::from_reader(reader)?; rule(&data); Ok(()) } fn main() { if let Err(e) = start() { eprintln!("运行出错: {}", e); std::process::exit(1); } }
额外优化点说明
#[serde(borrow)]的作用:让结构体直接借用JSON中的字符串,避免解析时复制字符串,节省内存和时间。- 哈希表索引:把
el数组转换成以eu为key的哈希表,让内层查找从O(N)变成O(1),如果el数组很大,性能提升会非常显著。 - 迭代器代替索引循环:Rust的迭代器比手动索引更高效,也更符合语言习惯。
调整后,这段代码的性能应该能轻松超过Go版本——毕竟Rust的静态类型和零开销抽象不是吹的!
内容的提问来源于stack exchange,提问作者Fmstrat
相关产品推荐
相关产品推荐

