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

spawn_blocking: this program silently fails #2116

Closed
njaard opened this issue Jan 14, 2020 · 6 comments
Closed

spawn_blocking: this program silently fails #2116

njaard opened this issue Jan 14, 2020 · 6 comments

Comments

@njaard
Copy link

njaard commented Jan 14, 2020

Version

└── tokio v0.2.9
└── tokio-macros v0.2.3

Platform

Linux audax 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u2 (2019-11-11) x86_64 GNU/Linux

Description

This program compiles without warnings:

#[tokio::main]
async fn main()
{
    tokio::task::spawn_blocking( || eprintln!("hello") );
}

Expected behavior

At compile time, I should get a warning saying that the function will run until it is awaited on.

Actual behavior

The program compiles cleanly but never (though correctly) runs the closure with the eprintln!.

@njaard njaard changed the title spawn_blocking, block_on: this program silently fails spawn_blocking: this program silently fails Jan 14, 2020
@Gowee
Copy link
Contributor

Gowee commented Jan 16, 2020

the function will run until it is awaited on.

Not exactly. I think it just cannot get a chance to run before the main thread exits.

use tokio::time::delay_for;
use std::time::Duration;
#[tokio::main]
async fn main()
{
    tokio::task::spawn_blocking( || eprintln!("hello") );

    delay_for(Duration::from_millis(100)).await;
    println!("100 ms have elapsed");
}

// hello
// 100 ms have elapsed

@njaard
Copy link
Author

njaard commented Jan 16, 2020

Hi @Gowee

the function will run until it is awaited on.

Not exactly. I think it just cannot get a chance to run before the main thread exits.

Sorry, I meant to say that it will not run until it's awaited on.

I think you misinterpret my report. Let me by analogy show you a function that returns a Result:

fn result() -> Result<String, ()>;

result();
//   = note: this `Result` may be an `Err` variant, which should be handled

I'm suggesting that spawn_blocking returns a future, and the future is discarded. Like the Result, something needs to be done with the future. If it were awaited on, then the program would complete as expected. So the compiler should emit a warning saying that, like this Result example, the Future should be handled.

@LucioFranco
Copy link
Member

@njaard so I agree that would be handy but the issue is that there are cases where you don't want to actually handle the JoinHandle. Because JoinHandle doesn't actually drive anything if the runtime stays alive for long enough the spawned future/blocking task will still complete. So in the end adding a must use would mean that users would then need to add allow's in places where they don't want to use it which I think is a worse UX than the issue you ran into.

@njaard
Copy link
Author

njaard commented Jan 16, 2020

@LucioFranco I think the current approach is so error prone that it's worthwhile to add it anyway.

Anyway, we can do let _ = ... as we do today with Result.

@LucioFranco
Copy link
Member

@njaard looks like if you change your code to use std its the same thing with no warning:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=ec366f0b5600b803f1319d4a56389880

So if that is the case I would think that this should be fixed in std then in tokio. Since, technically this is possible in std I don't think its worth while fixing here either.

The big difference with std too is that you need to explicitly join the tread while tokio allows you await directly to do that.

@Darksonn
Copy link
Contributor

Closing in favor of #1830.

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

4 participants