gpt4 book ai didi

asynchronous - 直接使用Future或包装在异步移动 block 之间的区别

转载 作者:行者123 更新时间:2023-12-03 11:43:52 24 4
gpt4 key购买 nike

我想知道为什么将代码从直接在Future中使用tokio::spawn更改为使用async move块可以使代码编译。
直接使用:

struct ClientMsg {
...
resp: oneshot::Sender<Bytes>,
}

async fn client_thread(
mut rx: Receiver<ClientMsg>,
client: Client,
) -> Result<(), Box<dyn Error>> {
while let Some(msg) = rx.recv().await {
...
let response = client.get(url).send().await?.bytes().await?;
msg.resp.send(response).unwrap();
}
Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
...
let (tx, rx) = mpsc::channel(5);
tokio::spawn(client_thread(rx, client)); // <--- Difference is here

Ok(())
}
异步块:
struct ClientMsg {
...
resp: oneshot::Sender<Bytes>,
}

async fn client_thread(
mut rx: Receiver<ClientMsg>,
client: Client,
) -> Result<(), Box<dyn Error>> {
while let Some(msg) = rx.recv().await {
...
let response = client.get(url).send().await?.bytes().await?;
msg.resp.send(response).unwrap();
}
Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
...
let (tx, rx) = mpsc::channel(5);
tokio::spawn(async move { client_thread(rx, client) }); // <-- Difference is here

Ok(())
}
请注意以下 use:
use bytes::Bytes;
use reqwest::Client;

use tokio::sync::{
mpsc::{self, Receiver},
oneshot,
};
use url::Url;
直接使用代码因以下原因而失败:
error[E0277]: `(dyn StdError + 'static)` cannot be sent between threads safely
--> src/main.rs:44:5
|
44 | tokio::spawn(client_thread(rx, client, base_url));
| ^^^^^^^^^^^^ `(dyn StdError + 'static)` cannot be sent between threads safely
|
::: /home/jeanluc/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.2.0/src/task/spawn.rs:130:20
|
130 | T::Output: Send + 'static,
| ---- required by this bound in `tokio::spawn`
|
= help: the trait `Send` is not implemented for `(dyn StdError + 'static)`
= note: required because of the requirements on the impl of `Send` for `Unique<(dyn StdError + 'static)>`
= note: required because it appears within the type `Box<(dyn StdError + 'static)>`
= note: required because it appears within the type `std::result::Result<(), Box<(dyn StdError + 'static)>>`
client_thread的返回类型与 main函数完全相同,但是它与Tokio一起运行没有任何问题。此外, error type from reqwest 实现 Send

最佳答案

完成后,将函数调用包装在async {}块中是行不通的。运行时,它将调用该函数,该函数将创建 future ,并仅返回它。永远不会对其进行轮询,因此永远不会取得进展。直接使用它或与.await一起使用可确保对其进行轮询。

use futures::executor::block_on; // 0.3.12

async fn f(s: &str) {
println!("ran {}", s);
}

fn main() {
block_on(f("first"));
block_on(async { f("second") }); // this doesn't print
block_on(async { f("third").await });
}
ran first
ran third
由于 future 不会持续存在,因此它不会最终影响 async {}块的特征,因此可以是 Send.await会再次遇到相同的问题。

在您的情况下,您需要做的就是确保将来实现 Send,以便可以与 tokio::spawn一起运行。解决方法是确定所返回的 Error特性实现了 Send:
async fn client_thread(
mut rx: Receiver<ClientMsg>,
client: Client,
) -> Result<(), Box<dyn Error + Send>> {
// ... ^^^^^^
}

关于asynchronous - 直接使用Future或包装在异步移动 block 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66295966/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com