出于好奇,我写了下面的程序,它每秒滴答X次,应该非常接近目标滴答数,但不知何故,它总是落后很多。
例如,对于一个2秒的基准测试,输出是(它应该是2*64 -> 128)。在发布模式下构建并不能解决这个问题:
Starting benchmark 2s with length
Benchmark started.
Ticked 83 in 2 seconds
字符串
其他长度也是一样的,例如5秒产生196,应该是320。实际上应该更多,因为我让它运行多一点。
是因为Arc Mutex
速度慢,还是还有其他原因?瓶颈在哪里?
use std::{ time::{ SystemTime, UNIX_EPOCH }, sync::Arc };
use tokio::{ time::{ sleep, Duration }, sync::Mutex };
const TICK_COUNT: u64 = 64;
const BENCHMARK_LENGTH: u64 = 2;
#[tokio::main]
async fn main() {
let tick_count = 0;
let interval = 1000 / TICK_COUNT;
let shared = Arc::new(Mutex::new(tick_count));
let start_time = SystemTime::now();
println!("Starting benchmark {}s with length", BENCHMARK_LENGTH);
let displayed = shared.clone();
let incrementer = shared.clone();
tokio::spawn(async move {
loop {
if
start_time.duration_since(UNIX_EPOCH).unwrap() +
Duration::from_secs(BENCHMARK_LENGTH) <
SystemTime::now().duration_since(UNIX_EPOCH).unwrap()
{
println!("Ticked {} in {} seconds", displayed.lock().await, BENCHMARK_LENGTH);
std::process::exit(0);
}
sleep(Duration::from_millis(500)).await;
}
});
tokio::spawn(async move {
loop {
sleep(Duration::from_millis(interval)).await;
*incrementer.lock().await += 1;
}
});
let _ = tokio::spawn(async move {
println!("Benchmark started.");
loop {
sleep(Duration::from_secs(1)).await;
}
}).await;
}
型
1条答案
按热度按时间hxzsmxv21#
我已经在我的计算机上尝试了你的程序。复制
*incrementer.lock().await += 1;
语句并没有改变行为(计数因此简单地相乘),因此减速不是由于Mutex
。此外,我用原子整数替换了Mutex
,行为仍然是一样的。cargo flamegraph
报告了在ThreadParker::futex_wait()
(parking_lot
的)下面的系统调用中花费的大量时间,这证实了我在评论中表达的直觉:大部分时间都花在操作系统挂起/恢复tokio
运行时的底层线程上。关于数值,我在2秒内获得122个滴答,离预期的128不远。使用128
TICK_COUNT
,我在2秒内获得240而不是256,使用256TICK_COUNT
,我在2秒内获得466而不是512。这并不理想,但离预期值不远。也许你的操作系统不如我的React快?(我使用的是非常普通的Linux)