all*_*y87 2 asynchronous future rust
在Sendtrait的文档中,有一个很好的例子说明了 Rc 之类的东西不是这样的Send,因为在两个不同的线程中克隆/删除会导致引用计数不同步。
然而,不太清楚的是,为什么在 a 中的Send一个await点上持有对非类型的绑定async fn会导致生成的未来也是非类型Send。当编译器在异步手册的变通方法一章中过于保守时,我能够找到变通方法,但它并没有回答我在这里提出的问题。
也许有人可以举例说明为什么在 a 中有一个非Send类型是Future可以的,但将它放在anawait上却不是?
当您.await在异步函数中使用时,编译器会在幕后构建一个状态机。每个都.await引入了一个新状态(当它等待某事时),中间的代码是状态转换(又名任务),这将根据一些外部事件(例如来自 IO 或计时器等)触发。
每个任务都被调度为由异步运行时执行,它可以选择使用与前一个任务不同的线程。如果状态转换在线程之间发送是不安全的,那么结果Future也不是Send这样,如果您尝试在多线程运行时中执行它,则会出现编译错误。
a Future not be完全可以Send,它只是意味着您只能在单线程运行时中执行它。
也许有人可以举例说明为什么在 a 中有一个非
Send类型是Future可以的,但将它放在anawait上却不是?
考虑以下简单示例:
async fn add_votes(current: Rc<Cell<i32>>, post: Url) {
let new_votes = get_votes(&post).await;
*current += new_votes;
}
Run Code Online (Sandbox Code Playgroud)
编译器将构造一个这样的状态机(简化):
enum AddVotes {
Initial {
current: Rc<Cell<i32>>,
post: Url,
},
WaitingForGetVotes {
current: Rc<Cell<i32>>,
fut: GetVotesFut,
},
}
Run Code Online (Sandbox Code Playgroud)
impl AddVotes {
fn new(current: Rc<Cell<i32>>, post: Url) {
AddVotes::Initial { current, post }
}
fn poll(&mut self) -> Poll {
match self {
AddVotes::Initial(state) => {
let fut = get_votes(&state.post);
*self = AddVotes::WaitingForGetVotes {
current: state.current,
fut
}
Poll::Pending
}
AddVotes::WaitingForGetVotes(state) => {
if let Poll::Ready(votes) = state.fut.poll() {
*state.current += votes;
Poll::Ready(())
} else {
Poll::Pending
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在多线程运行时,每次调用poll可能是从不同的线程,在这种情况下,运行时会移动的AddVotes调用之前,其他线程poll就可以了。这将不起作用,因为Rc不能在线程之间发送。
但是,如果未来只是Rc在同一个状态转换中使用 an ,那就没问题了,例如,如果votes只是一个i32:
async fn add_votes(current: i32, post: Url) -> i32 {
let new_votes = get_votes(&post).await;
// use an Rc for some reason:
let rc = Rc::new(1);
println!("rc value: {:?}", rc);
current + new_votes
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,状态机将如下所示:
enum AddVotes {
Initial {
current: i32,
post: Url,
},
WaitingForGetVotes {
current: i32,
fut: GetVotesFut,
},
}
Run Code Online (Sandbox Code Playgroud)
在Rc因为它是建立和状态变化(任务)中的下降并不在状态机拍摄的,所以整个状态机(又名Future)仍然是Send。