在Rust(以及其他编程语言)中,await
关键字用于指示异步函数体中的挂起点。然而,我注意到,与其他编程语言(Python gather
,Swift withTaskGroup
,JavaScript Promise.all
等)相反,Rust不需要并且会拒绝在Tokyo::join!
宏之后出现await
。
例如,在这个async
函数中,在join!
之后没有涉及await
:
use tokio::{io::Result, time::{sleep, Duration}, join};
async fn work() -> String {
sleep(Duration::from_secs(2)).await;
String::from("Work done")
}
#[tokio::main]
async fn main() -> Result<()> {
println!("Awaiting…");
let (o1, o2) = join!(
work(),
work(),
); // No `.await`
println!("{}, {}", o1, o2);
Ok(())
}
是否有技术原因导致join!
宏不返回某种聚合的Future
或可以被await
绑定的连接句柄?
这种隐式的await
令人困惑,因为这个异步函数乍一看似乎没有任何挂起点(因此不需要是async
),我认为这可能会破坏async-await
模式的目的,即寻求使挂起点显式。
1条答案
按热度按时间nimxete21#
如果展开宏(可以在Rust Playground的Tools菜单中完成),您将看到如下代码:
最后的
await
是展开式中唯一的await
。因此,没有任何技术原因可以解释为什么宏不能被写入不包含await
。然而,让我们看看历史。join
宏是在commit 7079bcd60975f592e08fcd575991f6ae2a409a1f(PR #2158)中引入的,在那里没有太多的讨论,但它在futures
库中有一个前身,在commit d67e2936c21a4d663814e38b06ce38d85bb02e9b(PR #1051)中引入。关于原始实现需要注意的一点是,与时雄中当前的实现不同,它 * 是 * 严重基于异步上下文(
poll!
和pending!
宏依赖于它):此外,PR中还进行了一些讨论:
MajorBreakfast于2018年6月28日评论
await
的宏应该以某种方式标记。或者,它们都可以使用async
块,并需要await
围绕它们await!(join![a, b])
。这看起来很糟糕,因为await!
目前是一个宏,但将来不会是。心理模型更简单,你可以在任何地方使用它,而不仅仅是在异步函数中。cramertj发表于2018年6月28日
@MajorBreakfast
select!
需要在内部执行await!
(而不是提供一个future作为结果),以允许编译器更智能地控制流(例如:允许return
正常工作,使初始化检查能够理解可能发生中断的不同条件等)。由于select!
不返回一个future,我认为join!
返回一个future会令人困惑--这两者看起来有点像自然的double,而且令人惊讶的是,它们在这方面的工作方式不同。因此,
select!
受益于不引入新的异步块,而是将其自身合并到调用者的异步块中,并且join!
被设计为具有与select!
相同的字符,即使它本身没有受益。