注释println后Rust程序循环次数剧增?IO操作影响QPS吗?
Rust中IO操作对循环计数及请求数的影响解析
问题场景与代码
基于Rust消息传递模型修改的代码如下:
use std::sync::mpsc; use std::thread; fn main() { let (tx1, rx) = mpsc::channel(); thread::spawn(move || { tx1.send("hi2").unwrap(); }); let mut count = 0; loop { match rx.try_recv() { Ok(msg) => { println!("{:?}", msg); break; } Err(_) => { // 不同IO操作会影响count值 // println!("not yet"); count += 1; } } } print!("{:?}", count) }
运行不同IO操作时的count值差异:
- 注释所有IO操作:
count约1646以上且波动大 - 启用
println!("not yet");:count仅10-20左右 - 替换为
std::io::stdout().write(b"not yet").unwrap();:count约350-380 - 替换为带缓冲的写入:
let mut buffer = std::io::BufWriter::new(std::io::stdout()); buffer.write(b"not yet").unwrap();count约82
差异原因解析
核心在于线程调度与CPU时间片分配:
- 无IO操作时,主线程是纯CPU密集型循环,会持续抢占CPU时间片,子线程很难获得执行机会完成
send操作,因此主线程会循环数千次才收到消息,count值极高。 - 加入IO操作后,IO调用会触发线程阻塞,主线程主动让出CPU时间片,操作系统会调度子线程执行,子线程能更早完成
send,所以主线程循环次数大幅减少。
不同IO操作的差异源于各自的阻塞耗时与系统调用次数:
println!:内部包含格式化、缓冲刷新等逻辑,单次调用耗时最长,阻塞时间久,子线程能更早被调度,count最低。- 直接
stdout().write:无缓冲,每次调用都会触发系统调用,耗时比带缓冲的写入长,count居中。 BufWriter:通过批量写入减少系统调用次数,阻塞耗时最短,子线程被调度的时机稍晚,count比println!高但远低于无IO场景。
最终疑问解答:IO操作差异是否影响每秒请求数?
会直接影响。原因如下:
- 纯CPU密集型循环会霸占CPU资源,导致处理请求的工作线程无法及时获得调度,请求处理延迟飙升,每秒能处理的请求数会显著下降。
- 带有IO操作(或主动让出CPU的操作,比如
std::thread::yield_now())的场景中,线程调度更均衡,工作线程有更多机会执行,整体请求吞吐量会提升。同时不同IO操作的耗时不同,对CPU调度的影响程度有差异,最终会导致每秒请求数出现波动。
内容的提问来源于stack exchange,提问作者ninetynin
相关产品推荐
相关产品推荐

