Как реализовать опрос на будущее неблокирующим образом в фьючерсах 0,3? - PullRequest
0 голосов
/ 12 сентября 2018

Обновление : Этот вопрос больше не актуален, поскольку Context удалено из подписи poll().


Я пытаюсь реализовать простой Future с ящиком для фьючерсов v0.3: открытие File.

Мое будущее сейчас выглядит так:

struct OpenFuture {
    options: OpenOptions,
    path:    PathBuf,
    output:  Option<io::Result<File>>,
}

Чтобы реализовать Future, я придумал это:

impl Future for OpenFuture {
    type Output = io::Result<File>;

    fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
        if let Some(file) = self.file.take() {
            Poll::Ready(file)
        } else {
            let waker = cx.waker().clone();
            cx.spawner().spawn_obj(
                Box::new(lazy(move |_| {
                    // self.file = Some(self.options.open(&self.path));
                    waker.wake();
                })).into(),
            );
            Poll::Pending
        }
    }
}

Если вывод Option::Some, его можно взять и будущее готово, это просто. Но если он не готов, я не хочу блокировать поток, как упомянуто в документации:

Реализация poll должна стремиться к быстрому возврату и никогда не должна блокироваться. Быстрый возврат предотвращает ненужное засорение потоков или циклов событий. Если заранее известно, что вызов poll может занять некоторое время, работа должна быть выгружена в пул потоков (или что-то подобное), чтобы poll мог быстро вернуться.

Так что я хочу разгрузить работу. Поскольку я Context передан методу poll, у меня есть доступ к Spawn и Waker. Spawn должен выполнить задачу, которая открывает файл. После того, как файл открыт, он уведомляется с помощью waker.wake().

Приведенный код не работает при раскомментировании строки из-за ошибки времени жизни:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
    |
    |                           Box::new(lazy(move |_| {
    |  _______________________________________^
    | |                             self.file = Some(self.options.open(&self.path));
    | |                             waker.wake();
    | |                         })).into(),
    | |_________________________^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body...
    |
    |               fn poll(mut self: PinMut<Self>, cx: &mut Context) -> Poll<Self::Output> {
    |  _____________^
    | |                 if let Some(file) = self.file.take() {
    | |                     Poll::Ready(file)
    | |                 } else {
...   |
    | |                 }
    | |             }
    | |_____________^
    = note: ...so that the types are compatible:
            expected std::pin::PinMut<'_, _>
               found std::pin::PinMut<'_, _>
    = note: but, the lifetime must be valid for the static lifetime...
    = note: ...so that the expression is assignable:
            expected std::future::FutureObj<'static, _>
               found std::future::FutureObj<'_, _>

Как это можно решить?

Кроме того, Spawn::spawn_obj возвращает Result. Как этот результат может быть обработан? Рекомендуется просто вернуть io::ErrorKind::Other?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...