How can i delay a task using async await

Hello everyone

i am trying to figure out, how to make a task delayed for 3 seconds, before proceeding

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

use tokio::time::delay_for;
use tokio::net::TcpListener;
use tokio::stream::StreamExt;

#[tokio::main]
async fn main() -> io::Result<()> {
    let mut listener = TcpListener::bind("127.0.0.1:3030").await?;
    let now = Instant::now();

    while let Some(stream) = listener.incoming().next().await {
        match stream {
            Ok(_) => {
                delay_for(Duration::from_secs(3)).await;
                println!("Finished after: {} seconds", now.elapsed().as_secs_f64());
            },
            Err(_) => {  }
        }
    }

    Ok(())
}

after running this command line for ((i=0;i<=5;i++)); do nc 127.0.0.1 3030 & done i expected all the tasks to be finished at almost the exact time, but the output was as follow

Finished after: 69.943965151 seconds
Finished after: 72.945856619 seconds
Finished after: 75.946934041 seconds
Finished after: 78.947990885 seconds
Finished after: 81.949795594 seconds
Finished after: 84.951644989 seconds

almost 3 seconds between each task, which equivalent to running them in sync, also i noticed that the nc process is still running in the background.

How can i resolve this issue?

Use tokio::spawn to spawn them. Async await is certainly able to run them concurrently, but you will have to tell it to do so, if that's what you want.

@alice

i am planning to use my code on a production server, and i am afraid that i may miss something up

does this look right ?

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

use tokio::prelude::*;
use tokio::time::delay_for;
use tokio::net::TcpListener;
use tokio::stream::StreamExt;

#[tokio::main]
async fn main() -> io::Result<()> {
    let mut listener = TcpListener::bind("127.0.0.1:3030").await?;
    let now = Instant::now();

    while let Some(stream) = listener.incoming().next().await {
        match stream {
            Ok(mut stream) => {
                tokio::spawn(async move {
                    delay_for(Duration::from_secs(3)).await;
                    println!("Finished after: {} seconds", now.elapsed().as_secs_f64());
                    stream.write(format!("Hello There").as_str().as_bytes()).await.unwrap();
                });
            },
            Err(_) => {  }
        }
    }

    Ok(())
}

I would probably log the error in a production context, but it looks OK.

1 Like