gpt4 book ai didi

asynchronous - 从闭包调用异步函数

转载 作者:行者123 更新时间:2023-12-03 11:34:44 27 4
gpt4 key购买 nike

我想在迭代器中使用的闭包内对 await 函数进行 async。需要闭包的函数在结构体实现中被调用。我无法弄清楚如何做到这一点。
这段代码模拟了我正在尝试做的事情:

struct MyType {}

impl MyType {
async fn foo(&self) {
println!("foo");

(0..2).for_each(|v| {
self.bar(v).await;
});
}

async fn bar(&self, v: usize) {
println!("bar: {}", v);
}
}

#[tokio::main]
async fn main() {
let mt = MyType {};
mt.foo().await;
}
显然,这将不起作用,因为闭包不是 async ,给我:
error[E0728]: `await` is only allowed inside `async` functions and blocks
--> src/main.rs:8:13
|
7 | (0..2).for_each(|v| {
| --- this is not `async`
8 | self.bar(v).await;
| ^^^^^^^^^^^^^^^^^ only allowed inside `async` functions and blocks

在寻找有关如何从非 async 函数调用 async 函数的答案后,我得出了以下结论:
tokio::spawn(async move {
self.bar(v).await;
});
但现在我正在解决终身问题:
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/main.rs:4:18
|
4 | async fn foo(&self) {
| ^^^^^
| |
| this data with an anonymous lifetime `'_`...
| ...is captured here...
...
8 | tokio::spawn(async move {
| ------------ ...and is required to live as long as `'static` here
这也不会让我感到惊讶,因为据我所知,Rust 编译器无法知道线程将存活多长时间。鉴于此,由 tokio::spawn 产生的线程可能比 MyType 类型的生命周期更长。
我想出的第一个解决方法是使 bar 成为关联函数,将我需要的所有内容复制到我的闭包中,并将其作为值传递给 bar 并使用 MyType::bar(copies_from_self) 调用它,但这变得越来越难看,因为有很多复制。这也感觉像是一种不知道生命周期如何运作的解决方法。
相反,我尝试使用 futures::executor::block_on ,它适用于像这篇文章中的简单任务:
(0..2).for_each(|v| {
futures::executor::block_on(self.bar(v));
});
但是当把它放在我使用第三方 library1 也使用 tokio 的现实生活示例中时,事情不再起作用。阅读文档后,我意识到 #[tokio::main] 是一个宏,它最终将所有内容都包装在 block_on 中,因此这样做将嵌套 block_on 。这可能是为什么在 async 中调用的 bar 方法之一只是停止工作而没有任何错误或日志的原因(在没有 block_on 的情况下工作,因此代码不应该是任何东西)。我联系了那些说我可以使用 for_each(|i| async move { ... }) 的作者,这让我更加困惑。
(0..2).for_each(|v| async move {
self.bar(v).await;
});
会导致编译错误
expected `()`, found opaque type`
我认为这是有道理的,因为我现在返回的是 future 而不是 () 。我对此的天真方法是尝试用这样的方法等待 future :
(0..2).for_each(|v| {
async move {
self.bar(v).await;
}
.await
});
但这让我回到了第一个方面,导致了以下编译错误,我也认为这是有道理的,因为我现在又回到在 await 闭包中使用 sync
only allowed inside `async` functions and blocks` since the 
这一发现也让我很难利用找到的答案,例如 herehere
毕竟这个 cargo 崇拜编程的问题基本上是, 是否可能,如果是的话,我如何从迭代器中的闭包 调用我的 async 函数(最好不产生线程以避免生命周期问题)?如果这是不可能的,那么惯用的实现会是什么样的?

1 This is the library/method used

最佳答案

Iterator::for_each 需要同步闭包,因此您不能在其中使用 .await(至少不能直接使用),也不能从中返回 future 。
一种解决方案是只使用 for 循环而不是 .for_each :

for v in 0..2 {
self.bar(v).await;
}
更通用的方法是使用 streams 而不是迭代器,因为它们是异步等效的(并且流上的等效方法通常也是异步的)。这不仅适用于 for_each,而且适用于大多数其他迭代器方法:
use futures::prelude::*;

futures::stream::iter(0..2)
.for_each(|c| async move {
self.bar(v).await;
})
.await;

关于asynchronous - 从闭包调用异步函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65871606/

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