Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blocking while popping #98

Open
rocket-matt opened this issue Feb 1, 2023 · 2 comments
Open

Blocking while popping #98

rocket-matt opened this issue Feb 1, 2023 · 2 comments

Comments

@rocket-matt
Copy link

Is there a better way to block until you have something to pop other than:

while input.is_empty() {}
let x = input.pop().unwrap();

?

@mgeier
Copy link
Owner

mgeier commented Feb 2, 2023

If you expect to be waiting for more than a few hundred nanoseconds, it's probably better to use a queue that has a proper blocking API? Maybe crossbeam::channel?

If you are only waiting for a short time, you can use rtrb, but depending on your application, you might want to add something like spin_loop() or some more fancy way to avoid maxing out the CPU. But other than that, I think your code is fine.

Another, not necessarily better way to do it:

let x = loop {
    if let Ok(item) = input.pop() {
        break item;
    }
    // relax a while
};

And yet another, but this time definitely worse way of doing it:

fn crazy(input: &mut rtrb::Consumer<i32>) -> i32 {
    input.pop().unwrap_or_else(|_| {
        // relax a while
        crazy(input)
    })
}
let x = crazy(&mut input);

Apart from being crazy, this will also quickly lead to a stack overflow.
I was just curious if that would work.

@gootorov
Copy link

In case anyone finds this useful, here's my approach:

let backoff = crossbeam_utils::Backoff::new();
loop {
    match consumer.pop() {
        Ok(item) => {
            backoff.reset();

            // do stuff with `item`
            // ...
        }
        Err(rtrb::PopError::Empty) => {
            if backoff.is_completed() {
                thread::sleep(Duration::from_micros(/* your desirable duration */));
            } else {
                backoff.snooze();
            }
        }
    }
}

This still keeps Producer::push very fast, while potentially trading off some latency on the consumer side.
As a bonus - if you replace thread::sleep with tokio::time::sleep/tokio_timerfd::sleep (or similar), then you can have a producer in sync code, and a consumer in async code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants