rust 什么是`File::poll_write()`的行为?

qv7cva1a  于 2023-04-06  发布在  其他
关注(0)|答案(1)|浏览(138)

我特别提到这个方法: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(_)

6ojccjat

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可能会被错误地唤醒,所以你不应该依赖于它(尽管我可能是错的,我不确定)。

相关问题