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

New lint suggestion: You're using a blocking operation when you could be using an async one #10794

Open
omarandlorraine opened this issue May 17, 2023 · 3 comments
Assignees
Labels
A-lint Area: New lints

Comments

@omarandlorraine
Copy link

omarandlorraine commented May 17, 2023

What it does

A lint which checks for blocking functions inside an async block.

One I know of (and the cause of a bug I ran into today) is std::thread::sleep, but there are others. (file operations, networking, ...). If such a function has an async counterpart, then the user could be warned of this fact.

Lint Name

unwise-block

Category

suspicious

Advantage

  • warn of badly behaving async programs

Drawbacks

  • might be too noisy

Example

use std::thread::sleep;
use std::time::Duration;
use tokio::signal::unix::signal;
use tokio::signal::unix::SignalKind;
use tokio::sync::mpsc;

async fn rx(rx: &mut mpsc::Receiver<()>) {
    loop {
        sleep(Duration::new(1, 0));
        if rx.try_recv().is_ok() {
            println!("got one splivet");
        }
    }
}

async fn tx(tx: mpsc::Sender<()>) {
    let mut stream = signal(SignalKind::user_defined1()).unwrap();

    loop {
        stream.recv().await;
        println!("sending one splivet");
        tx.send(()).await.unwrap();
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let (stx, mut srx) = mpsc::channel::<()>(5);

    tokio::join!(tx(stx), rx(&mut srx));
}

Could be written as:

use std::thread::sleep;
use std::time::Duration;
use tokio::signal::unix::signal;
use tokio::signal::unix::SignalKind;
use tokio::sync::mpsc;

async fn rx(rx: &mut mpsc::Receiver<()>) {
    loop {
        tokio::time::sleep(Duration::new(1, 0)).await;
        if rx.try_recv().is_ok() {
            println!("got one splivet");
        }
    }
}

async fn tx(tx: mpsc::Sender<()>) {
    let mut stream = signal(SignalKind::user_defined1()).unwrap();

    loop {
        stream.recv().await;
        println!("sending one splivet");
        tx.send(()).await.unwrap();
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let (stx, mut srx) = mpsc::channel::<()>(5);

    tokio::join!(tx(stx), rx(&mut srx));
}

Note the different way to sleep in the rx function.

@omarandlorraine omarandlorraine added the A-lint Area: New lints label May 17, 2023
@y21
Copy link
Member

y21 commented Jun 7, 2023

I like this idea! Although there are some exceptions we should probably make, such as with Mutex. Using an async Mutex only makes sense when the guard is held across an await point. In most other cases, it's totally fine to use the Mutex from the standard library (or parking_lot), even in an async context

@J-ZhengLi
Copy link
Member

J-ZhengLi commented Sep 25, 2023

Well since I have wrote a simple but similar one in the past for my own fork of clippy, I'll take the chance make it official, lol

@rustbot claim

@tv42
Copy link

tv42 commented Jun 12, 2024

This looks like a duplicate (with refinements, suggesting what use instead) of #4377.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants