#asynchronous #rust #future #tokio
#асинхронный #Ржавчина #будущее #tokio
Вопрос:
Как реализовать Futures::poll
следующий код, который будет вызывать async
метод с полным правом собственности на self
?
use anyhow::Error;
use futures::Future;
use futures::channel::oneshot;
use futures::task::{Context, Poll};
use std::pin::Pin;
struct MyLongTask {
rx: oneshot::Receiver<()>,
}
impl MyLongTask {
// The method and full ownership to `self` is important to keep!
async fn recv(mut self) -> Result<(), Error> {
self.rx.await.map_err(|_| Error::msg("can't recv"))
}
}
// TryFuture not necessary here
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(self: Pin<amp;mut Self>, cx: amp;mut Context<'_>) -> Poll<Self::Output> {
todo!("how to `self.recv().await` here?")
}
}
fn main() { }
Игровая площадка, если это необходимо.
Комментарии:
1. В чем преимущество создания
MyLongTask
future вместо прямого вызоваrx.await.map_err(...)
? Какова цель?2. Это упрощенный пример структуры со многими полями, которые необходимо использовать.
3. Если
MyLongTask
имеет много полей и нуждается в использовании и обработкеrecv
, зачем создаватьMyLongTask
себе будущее?my_long_task.recv()
уже возвращает future, который делает то, что вы хотите, нет?
Ответ №1:
Вы не можете вызвать self.recv()
inside poll
во-первых, потому что он не принадлежит self
, а во-вторых, потому что это не async
так. Future::poll
является синхронным, но должен быстро возвращаться независимо от того, готово ли возвращаемое значение (в этом вся идея Poll::Pending
). В вашем случае вам следует просто делегировать poll
to self.rx
: (игровая площадка)
impl Future for MyLongTask {
type Output = Result<(), Error>;
fn poll(mut self: Pin<amp;mut Self>, cx: amp;mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(amp;mut self.rx).poll(cx) {
Poll::Ready(x) => Poll::Ready(x.map_err(|_| Error::msg("can't recv"))),
Poll::Pending => Poll::Pending,
}
}
}
Теперь вместо использования task.recv().await
вы можете просто сделать task.await
.
Я бы также посоветовал вам либо реализовать, Future
либо предоставить recv
метод.
В противном случае вы можете столкнуться с проблемами позже, когда измените одну реализацию и забудете изменить другую.
Комментарии:
1. «а во-вторых, потому что это не
async
так » — чтобы быть педантичным, вы можете вызватьasync
функцию из не-async
одного, вы просто не можете.await
этого. Возвращенное будущее просто ничего не сделает, если что-то не продвинет его вперед.2. Это не совсем то, что мне было нужно, но тоже полезно.