简体   繁体   English

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

[英]Rust futures / async - await strange behavior

Edit:编辑:

I swapped all of the future / async calls to instead just spawn a new thread, but still the program takes 15 seconds to run, instead of the expected 1 second.我交换了所有未来/异步调用,而不是只生成一个新线程,但程序仍然需要 15 秒才能运行,而不是预期的 1 秒。 What is the reason?是什么原因? total_send_time is time taken to spawn a new thread + time spent sleeping before launching a new thread. total_send_time是产生一个新线程所花费的时间 + 启动一个新线程之前花费的睡眠时间。 Note: I am trying to send requests uniformly at a certain rate.注意:我试图以一定的速率统一发送请求。

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);
}

Original:原来的:

I am new to rust and I was reading up on using futures and async / await in rust, and built a simple tcp server using it.我是 rust 的新手,我正在阅读有关在 rust 中使用futuresasync / await的内容,并使用它构建了一个简单的 tcp 服务器。 I then decided to write a quick benchmark, by sending requests to the server at a constant rate, but I am having some strange issues.然后我决定通过以恒定速率向服务器发送请求来编写一个快速基准测试,但我遇到了一些奇怪的问题。

The below code should send a request every 0.001 seconds, and it does, except the program reports strange run times.下面的代码应该每 0.001 秒发送一次请求,并且确实如此,除了程序报告奇怪的运行时间。 This is the output:这是 output:

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

Obviously getting system time and calculating time to sleep has some cost, but surely not 14 seconds.显然,获取系统时间和计算睡眠时间有一些成本,但肯定不是 14 秒。 What have I done wrong?我做错了什么?

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)
}

You are not measuring the elapsed time correctly:您没有正确测量经过的时间:

  1. total_send_time measures the duration of the spawn() call, but as the actual task is executed asynchronously, start_in.elapsed() does not give you any information about how much time the task actually takes. total_send_time测量spawn()调用的持续时间,但由于实际任务是异步执行的,因此start_in.elapsed()不会为您提供有关任务实际花费多少时间的任何信息。

  2. The ran in time, as measured by start.elapsed() is also not useful at all.start.elapsed()测量的ran in时间也根本没有用。 As you are using blocking sleep operation, you are just measuring how much time your app has spent in the std::thread::sleep()当您使用阻塞睡眠操作时,您只是在测量您的应用程序在std::thread::sleep()中花费了多少时间

  3. Last but not least, your time_to_sleep calculation is completely incorrect, because of the issue mentioned in point 1.最后但同样重要的是,由于第 1 点中提到的问题,您的time_to_sleep计算完全不正确。

Edit编辑

As I've already explained in my previous answer, your program takes 15 seconds to run, because you do not calculate the time to sleep properly.正如我在之前的回答中已经解释的那样,您的程序需要 15 秒才能运行,因为您没有计算正确睡眠的时间。 There are also other mistakes such as using blocking sleep in an async function, etc;还有其他错误,例如在异步 function 中使用阻塞睡眠等; Here is a corrected version:这是一个更正的版本:

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