繁体   English   中英

Rust 期货/异步 - 等待奇怪的行为

[英]Rust futures / async - await strange behavior

编辑:

我交换了所有未来/异步调用,而不是只生成一个新线程,但程序仍然需要 15 秒才能运行,而不是预期的 1 秒。 是什么原因? total_send_time是产生一个新线程所花费的时间 + 启动一个新线程之前花费的睡眠时间。 注意:我试图以一定的速率统一发送请求。

Interval between calls: 0.001 s
Ran in 15391 ms, total time: 1.0015188 s
use std::time::Duration;
use std::ops::Sub;
use std::net::TcpStream;
use std::io::Read;

const NANOSECOND: u64 = 1000000000;
const SECOND: u64 = 1;

const RPS: u64 = 1000;
const N: u64 = 1000;

fn send_request() {
    let mut stream = TcpStream::connect("127.0.0.1:8080").unwrap();
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).unwrap();
}

fn main() {
    let duration: u64 = ((SECOND as f64 / RPS as f64) as f64 * NANOSECOND as f64) as u64;
    println!("Interval between calls: {} s", (SECOND as f64 / RPS as f64));
    let start = std::time::Instant::now();
    let mut total_send_time: u128 = 0;
    for i in 0..N {
        let start_in = std::time::Instant::now();
        std::thread::spawn(move || send_request());
        let time_to_sleep = ((duration as i128 - start_in.elapsed().as_nanos() as i128) as i128).abs();
        total_send_time += start_in.elapsed().as_nanos();
        if time_to_sleep > 0 {
            std::thread::sleep(Duration::from_nanos(time_to_sleep as u64));
            total_send_time += time_to_sleep as u128;
        }
    }
    println!("Ran in {} ms, total time: {} s", start.elapsed().as_millis(), total_send_time as f64 / NANOSECOND as f64);
}

原来的:

我是 rust 的新手,我正在阅读有关在 rust 中使用futuresasync / await的内容,并使用它构建了一个简单的 tcp 服务器。 然后我决定通过以恒定速率向服务器发送请求来编写一个快速基准测试,但我遇到了一些奇怪的问题。

下面的代码应该每 0.001 秒发送一次请求,并且确实如此,除了程序报告奇怪的运行时间。 这是 output:

Interval between calls: 0.001 s
Ran in 15 s, total time: 1 s

显然,获取系统时间和计算睡眠时间有一些成本,但肯定不是 14 秒。 我做错了什么?

use async_std::net::TcpStream;
use futures::AsyncReadExt;
use std::time::Duration;
use async_std::task::spawn;
use std::ops::Sub;

const RPS: u64 = 1000;
const N: u64 = 1000;

async fn send_request() {
    let mut stream = TcpStream::connect("127.0.0.1:8080").await.unwrap();
    let mut buffer = [0; 1024];
    stream.read(&mut buffer).await.unwrap();
}

#[async_std::main]
async fn main() {
    let duration: u64 = ((1 as f64 / RPS as f64) as f64 * 1000000000 as f64) as u64;
    println!("Interval between calls: {} s", (1 as f64 / RPS as f64));
    let start = std::time::Instant::now();
    let mut total_send_time: u128 = 0;
    for _ in 0..N {
        let start_in = std::time::Instant::now();
        spawn(send_request());
        let time_to_sleep = ((duration as i128 - start_in.elapsed().as_nanos() as i128) as i128).abs();
        total_send_time += start_in.elapsed().as_nanos();
        if time_to_sleep > 0 {
            std::thread::sleep(Duration::from_nanos(time_to_sleep as u64));
            total_send_time += time_to_sleep as u128;
        }
    }
    println!("Ran in {} s, total time: {} s", start.elapsed().as_secs(), total_send_time / 1000000000)
}

您没有正确测量经过的时间:

  1. total_send_time测量spawn()调用的持续时间,但由于实际任务是异步执行的,因此start_in.elapsed()不会为您提供有关任务实际花费多少时间的任何信息。

  2. start.elapsed()测量的ran in时间也根本没有用。 当您使用阻塞睡眠操作时,您只是在测量您的应用程序在std::thread::sleep()中花费了多少时间

  3. 最后但同样重要的是,由于第 1 点中提到的问题,您的time_to_sleep计算完全不正确。

编辑

正如我在之前的回答中已经解释的那样,您的程序需要 15 秒才能运行,因为您没有计算正确睡眠的时间。 还有其他错误,例如在异步 function 中使用阻塞睡眠等; 这是一个更正的版本:

use std::time::{Duration, Instant};

const TASKS: u64 = 1000;
const TASKS_PER_SECOND: u64 = 1000;

#[async_std::main]
async fn main() -> std::io::Result<()> {
    let micros_per_task = Duration::from_micros(
        Duration::from_secs(1).as_micros() as u64 / TASKS_PER_SECOND
    );
    let mut spawn_overhead = Duration::default();

    let before_spawning = Instant::now();
    for _ in 0..TASKS {
        let task_start = Instant::now();
        async_std::task::spawn(task());
        let elapsed = task_start.elapsed();
        spawn_overhead += elapsed;

        if elapsed < micros_per_task {
            let sleep = micros_per_task - elapsed;
            async_std::task::sleep(sleep).await;
        }
    }
    let elapsed_spawning = before_spawning.elapsed();
    println!("Took {}ms to spawn {} tasks", elapsed_spawning.as_millis(), TASKS);
    println!("Micros spent in spawn(): {}", spawn_overhead.as_micros());

    Ok(())
}

async fn task() {
    async_std::task::sleep(Duration::from_millis(1000)).await;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM