How to cancel loop after 10s if no error in a test?

Hi,

I'm trying to implement a test that compares the output of 2 algorithms for at least 10 seconds of running.

I'm just starting rust, so maybe is there something I didn't got with the timeout function.

How to get the output when timeout is finished and pass it inside my loop to break it ?

Thanks for your help,

#[cfg(test)]
mod tests {
    use super::*;
    use rand::Rng;
    use std::time::Duration;
    use tokio::sync::oneshot;
    use tokio::time::timeout;

    #[tokio::test]
    async fn stress_test() {
        timeout(Duration::from_secs(10), async move {
            loop {
                let n: i32 = rand::thread_rng().gen_range(2..100);
                println!("Vector size : {} \n", n);

                let mut vec1: Vec<i32> = vec![];

                for _i in 0..n {
                    vec1.push(rand::thread_rng().gen_range(0..10000000));
                }

                println!("{:?} \n", vec1);

                let res1: i128 = pairwise_product_by_loop(&vec1);
                let res2: i128 = pairwise_product_by_max(&vec1);

                if res1 != res2 {
                    panic!("Wrong answer : {} vs {}\n", res1, res2);
                } else {
                    println!("OK");
                }

                // How do I stop the loop when we reach the end of the timeout ? Here I should put the break
            }
        })
        .await
        .unwrap();
    }
}```

Your async block doesn't contain any await points, so it's useless. You never give the runtime a chance to re-acquire control – your code is 100% synchronous and blocking, forever. You have to insert some asynchrony somewhere (e.g. after each invocation of either algorithm to be tested) in order for the timeout to fire at all. However, unless your two functions are themselves async, this doesn't guarantee that they will run for at most 10 seconds.

2 Likes

Thanks for the reply.

When I said I want the two functions run for a least 10 seconds, I meant I'm executing them multiple times (probably millions) for 10 seconds(the reason why I use a loop inside a timeout), so the stress test can be valid if no error encountered in this time.

So I don't get where I can put an await inside the loop. I tried next to the the println!("OK").await but I got the error message ``() is not a future. I don't get cause if you look at the timeout method, it accepts only a Future as a second parameter.

You can't await random things – println() is not async. You have to await something that is async. For example, you can tokio::time::sleep() for a short (possibly zero) duration.

It means that it accepts the (pending) "result" of an async operation. No magic there.

1 Like

Ok I succeeded in implementing it with your suggestion.

But I'm still very confused about it, and to put the sleep, I had to remove the unwrap(), and pass the timeout into this very ugly way ..

Any suggestion on how I can refactor this in a better way ? Maybe it will help me better understand and connect everything..

Thanks again!!

#[tokio::test]
async fn stress_test() {
        if let Err(_) = timeout(Duration::from_secs(10), async move {
            loop {
                let n: i32 = rand::thread_rng().gen_range(2..100);
                println!("Vector size : {} \n", n);

                let mut vec1: Vec<i32> = vec![];

                for _i in 0..n {
                    vec1.push(rand::thread_rng().gen_range(0..10000000));
                }

                println!("{:?} \n", vec1);

                let res1: i128 = pairwise_product_by_loop(&vec1);
                let res2: i128 = pairwise_product_by_max(&vec1);

                if res1 != res2 {
                    panic!("Wrong answer : {} vs {}\n", res1, res2);
                } else {
                    sleep(Duration::from_millis(0)).await;
                    println!("OK");
                }
            }
        })
        .await
        {} // <--- Very ugly..
    }
}

What do you mean by "had to"? What happens if you simply add the sleep().await; call? Please provide more context – it's not clear what else you are trying to do.

1 Like

I had this error, if I just add the sleep.

 panicked at 'called `Result::unwrap()` on an `Err` value: Elapsed(())'

I will try to explain with my words what I understood :

  • Timeout needs a future, so a pending "result" to start. As my function was synchronous and an infinite loop, I returned no pending..
  • By using sleep, my function could return a future, which is Sleep. So the timeout could start and return something.

Concerning unwrap :

  • timeout return an Error if the future not completes before the duration has elapsed, otherwise it will returns the value of the function (the future). As the function (future) couldn't complete before the duration was finished, timeout returns an Elapsed error and so unwrap throws it.

I can do something simply like this :

Don't hesitate to correct me if I'm wrong in my thinking. I really would like to understand.

    #[tokio::test]
    async fn stress_test() {
        let _timer = timeout(Duration::from_secs(10), async move {
            loop {
                let n: i32 = rand::thread_rng().gen_range(2..100);
                println!("Vector size : {} \n", n);

                let mut vec1: Vec<i32> = vec![];

                for _i in 0..n {
                    vec1.push(rand::thread_rng().gen_range(0..100));
                }

                println!("{:?} \n", vec1);

                let res1: i128 = pairwise_product_by_loop(&vec1);
                let res2: i128 = pairwise_product_by_max(&vec1);

                if res1 != res2 {
                    panic!("Wrong answer : {} vs {}\n", res1, res2);
                } else {
                    sleep(Duration::from_millis(0)).await;
                    println!("OK");
                }
            }
        })
        .await;
    }

Well, if a timeout is considered a successful test, you definitely can just go ahead and ignore the Result.

1 Like

Yes, and as I return nothing with my loop at the end of the timeout, timeout throws this Elapsed error. So the test considers it failed.

To make it successful, I can just ignore it, as you said.

Eureka, everything is connected in my head now, and I understood.

Thanks, you helped me a lot!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.