我特别提到这个方法:https://docs.rs/tokio/latest/tokio/io/trait.AsyncWrite.html#tymethod.poll_write。如果我对future的理解正确的话,这个poll
方法会被executor以两种可能的方式执行:在第一次调用.await
时,或者在发出任务的Waker
的信号时。
如果这是真的,那么我对函数的API感到困惑:
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize, io::Error>>;
当我第一次调用poll_write
时,我知道我需要传入buf
字节。然而,当Future再次被唤醒并重新调用poll函数时,buf
会发生什么?它会被丢弃吗?
请看这个例子:
struct MyWriter {
file: File,
my_val: i32
}
impl MyWriter {
fn new(file: File) -> Self {
Self {
file,
my_val: 0
}
}
fn get_val(&mut self) -> i32 {
let old = self.my_val;
self.my_val += 1;
old
}
}
impl Future for MyWriter {
type Output = i32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// Invoke some additional logic
let _ = self.my_logic();
let bytes = vec![];
bytes.append(self.get_val());
match self.file.poll_write(cx, bytes) {
Poll::Ready(_) => Poll::Ready(0),
_ => Poll::Pending
}
}
}
// What's the behaviour of the following?
let writer = MyWriter { file };
let ans = writer.await;
如果在第一次轮询时poll_write
没有准备好,那么该过程被放弃。这是否意味着self.my_logic()
被再次调用?既然这是一个“唤醒”状态,那么self.file.poll_write(cx, bytes)
现在做什么?它只是返回一个Poll::Ready(_)
吗?它只是“知道”,因为它被重新唤醒,它可以忽略bytes
吗?
编辑:
已将my_val
字段追加到writer结构。
在第一次运行poll
时,self.get_val()
返回0,因此我们尝试将0
写入文件。假设写入尚未准备好,因此我们返回pending。
最后,waker收到信号,再次调用poll
。这一次,self.get_val()
返回1。现在会发生什么?poll_write()
现在会尝试将1
写入文件吗?或者它会放弃这次写入,只从0
的最后一次写入中产生Poll::Ready(_)
?
1条答案
按热度按时间6ojccjat1#
然而,当Future再次被唤醒,poll函数被重新调用时,
buf
会发生什么?它会被丢弃吗?恰恰相反,只有最后一个
buf
被使用,那么文件就可以写了;所有先前的buf
s被丢弃。This is specified in the documentation:Poll::Pending
表示没有从提供的缓冲区写入数据。I/O对象当前不可写,但将来可能会变为可写。最重要的是,当前将来的任务被调度为在对象可写时取消停放。这是否意味着
self.my_logic()
被再次调用?MyWriter::poll()
将被再次调用,所以是的,my_logic()
也将被再次调用。它只返回一个
Poll::Ready(_)
吗?根据我上面引用的文档,它会立即写入字节并返回
Poll::Ready
。然而,据我所知,futures可能会被错误地唤醒,所以你不应该依赖于它(尽管我可能是错的,我不确定)。