Rust程序运行异常缓慢:Tick计数为何远低于预期?
问题分析与解决方案
你的程序tick数远低于预期,核心问题不是Arc<Mutex>的性能,而是时间计算逻辑错误、间隔的整数除法误差,以及退出时机的延迟。以下是具体问题和修复方案:
主要问题点
- 整数除法导致tick间隔偏差:
1000 / TICK_COUNT是整数除法,1000/64=15(u64类型),但实际需要的间隔是15.625ms,整数除法丢弃了小数部分,导致tick频率和预期基准不匹配。 - 退出检查的时机错误:退出任务的循环是先判断时间再sleep 500ms,这会让程序在基准时长到达后最多延迟500ms才退出,且检查频率过低会导致计时精度差。
- 时间比较逻辑的错误:用
SystemTime结合UNIX_EPOCH计算时间差的方式易受系统时间调整影响,且逻辑冗余,不适合测量程序运行时长。 - 冗余任务的无意义等待:第三个任务的
.await会让main函数无限等待该循环任务,完全多余。
修复后的代码
use std::{sync::Arc, time::Instant}; use tokio::{sync::Mutex, time::{sleep, Duration}}; const TICK_COUNT: u64 = 64; const BENCHMARK_LENGTH: u64 = 2; #[tokio::main] async fn main() { let tick_count = 0; // 使用浮点计算精确的tick间隔 let interval = Duration::from_secs_f64(1.0 / TICK_COUNT as f64); let shared = Arc::new(Mutex::new(tick_count)); let start_instant = Instant::now(); println!("Starting benchmark with length {}s", BENCHMARK_LENGTH); let displayed = shared.clone(); let incrementer = shared.clone(); // 退出检查任务:用Instant精确判断时间,提高检查频率减少延迟 tokio::spawn(async move { loop { sleep(Duration::from_millis(10)).await; if start_instant.elapsed() >= Duration::from_secs(BENCHMARK_LENGTH) { println!("Ticked {} in {} seconds", displayed.lock().await, BENCHMARK_LENGTH); std::process::exit(0); } } }); // Tick任务:使用精确的间隔时间 tokio::spawn(async move { loop { sleep(interval).await; *incrementer.lock().await += 1; } }); // 保持main运行 loop { sleep(Duration::from_secs(1)).await; } }
修复说明
- 精确的tick间隔:用
Duration::from_secs_f64(1.0 / TICK_COUNT as f64)计算出15.625ms的精确间隔,确保每秒执行64次tick。 - 单调计时器
Instant:Instant::elapsed()直接获取程序运行的精确时长,不受系统时间调整影响,时间判断更可靠。 - 优化退出检查频率:将退出检查的sleep间隔改为10ms,大幅减少退出延迟,确保程序在基准时长到达后尽快退出。
- 移除冗余任务:去掉无意义的第三个任务,直接在main中做无限sleep保持进程运行。
关于Arc<Mutex>的性能疑问
你的场景中Arc<Mutex>不是性能瓶颈:只有tick任务频繁获取锁(每次tick一次),退出任务仅在最后获取一次锁,几乎没有竞争。tokio的Mutex是异步锁,性能远高于标准库的同步锁,完全能支撑每秒64次的锁操作。
内容的提问来源于stack exchange,提问作者geo10
相关产品推荐
相关产品推荐

