I'm wondering why changing the code from using a Future directly to using it in an async move block makes a difference. Passing it to tokio::spawn directly yields an error:
use std::error::Error;
use tokio::sync::{mpsc::{self, Receiver}, oneshot::Sender};
struct Msg {
resp: Sender<Vec<u8>>,
}
async fn client_thread(
mut rx: Receiver<Msg>,
) -> Result<(), Box<dyn Error>> {
while let Some(msg) = rx.recv().await {
msg.resp
.send(vec![]) // return some data
.unwrap();
}
Ok(())
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let (_tx, rx) = mpsc::channel(5);
tokio::spawn(client_thread(rx));
Ok(())
}
error[E0277]: `(dyn std::error::Error + 'static)` cannot be sent between threads safely
--> src/main.rs:23:5
|
23 | tokio::spawn(client_thread(rx)); // <--- Difference is here
| ^^^^^^^^^^^^ `(dyn std::error::Error + 'static)` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `(dyn std::error::Error + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn std::error::Error + 'static)>`
= note: required because it appears within the type `Box<(dyn std::error::Error + 'static)>`
= note: required because it appears within the type `Result<(), Box<(dyn std::error::Error + 'static)>>`
note: required by a bound in `tokio::spawn`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.21.0/src/task/spawn.rs:128:20
|
128 | T::Output: Send + 'static,
| ^^^^ required by this bound in `tokio::spawn`
But changing it to an async block makes it compile:
tokio::spawn(async move { client_thread(rx) });
The return type of client_thread is exactly the same as the main function, however, which runs with Tokio without any problems. Moreover, the error type from reqwest implements Send.