【问题标题】:Wrapping AsyncRead `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement包装 AsyncRead `self` 具有匿名生命周期 `'_` 但它需要满足 `'static` 生命周期要求
【发布时间】:2021-04-24 15:08:15
【问题描述】:

我正在尝试将AsyncRead 包装在另一个AsyncRead 中(并对其进行一些数据处理)。但是,当尝试存储 .read()Future 时,我遇到了终身问题:self has an anonymous lifetime '_ but it needs to satisfy a 'static lifetime requirement

代码:

pub struct AsyncReadWrap {
    input: Pin<Box<dyn AsyncRead + 'static>>,
    future: Option<Pin<Box<dyn Future<Output = std::io::Result<usize>>>>>
}

impl AsyncReadWrap {
    pub fn new(input: impl AsyncRead + Unpin + 'static) -> AsyncReadWrap {
        AsyncReadWrap {
            input: Box::pin(input),
            future: None
        }
    }
}

impl AsyncRead for AsyncReadWrap {
    fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<std::io::Result<()>> {
        
        let mut buffer = [0u8; 2048];
        let future = self.input.as_mut().read(&mut buffer);
        self.future = Some(Box::pin(future));
       
        Poll::Pending
    }
}

我是异步的新手,奇怪的是在 poll 函数中没有一些简单的方法来 await。谢谢。

【问题讨论】:

    标签: asynchronous rust


    【解决方案1】:

    您不能从poll 函数调用await,因为await 可能会多次调用poll,并将控制权交还给执行程序。单个poll 调用可能只会产生一次,并且只能通过另一个poll 调用来恢复。轮询和期货是 async/await 的构建块 - 在使用较低级别的实现时,您不能使用较高级别的抽象。

    您当前代码的问题在于您的结构是自引用的input.read() 返回一个可以从input 借用的未来:

    // `Read` borrows from `self` and `buf`
    fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self> 
    

    您不能将返回的未来存储在您的结构中,因为storing a value and a reference to that value in the same struct is problematic

    要创建AsyncRead 包装器,您可以在内部AsyncRead 上调用poll_read。当poll_read返回Ready时,缓冲区将被读取的值填满,你可以对其进行数据处理:

    impl AsyncRead for AsyncReadWrap {
        fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, mut buf: &mut ReadBuf<'_>) -> Poll<std::io::Result<()>> {
            match self.input.as_mut().poll_read(cx, &mut buf) {
                Poll::Ready(res) => {
                    // do stuff with `buf`
                    Poll::Ready(res)
                },
                Poll::Pending => Poll::Pending
            }
        }
    }
    

    poll_read 函数内执行更多async 操作将变得复杂,因为您必须跟踪您的AsyncRead 实现将处于的多个状态。async/await 是一个抽象较低级别的未来状态机。如果您不一定要求实现AsyncRead,则可以完全避免使用较低级别的future,只需将其设为async 方法:

    pub async fn read(mut input: impl AsyncRead + Unpin) -> Vec<u8> {
        let mut buf = [0u8; 1024];
        input.read(&mut buf).await;
        // ...
        buf.to_vec()
    }
    

    如果你选择走低级路线,这里有一些有用的资源:

    【讨论】:

    • 感谢您的解释,帮助我理解了这一点。我之前已经尝试过poll_read,但是由于某种原因它无法多次阅读。可能是我的代码中的错误。如果我的流解决方法失败,将重试。
    • @MakaloneLOgman Futures 可能很难手动编写,而且很容易出错,因为流程可能不直观。另请注意,如果您返回Poll::Pending,除非您tell it to wake you up,否则执行程序将永远不会再次轮询您。如果您选择走这条路,我将在答案中链接一些资源,以帮助您开始使用较低级别的异步。
    • 是的,正在尝试,任何事情都会有所帮助。
    • 有趣的是,有用资源中只有 5 个唯一单词中的 1 个字面上是“痛苦的”,而另外两个是“Async”和“Await”
    • @oliver 好吧,低级异步 Rust 很难,这是毫无疑问的。只是async/await还很新,很多底层细节还在暴露给初学者。
    猜你喜欢
    • 2022-06-13
    • 1970-01-01
    • 1970-01-01
    • 2014-09-10
    • 2017-09-28
    • 2015-04-22
    • 2017-07-04
    • 1970-01-01
    • 2021-11-20
    相关资源
    最近更新 更多