Как мне реализовать Future, который проснулся из другого потока в Futures 0.2? - PullRequest
0 голосов
/ 19 мая 2018

Я пытаюсь найти простой способ реализации черты Future из будущего ящика, версия 0.2.1:

extern crate futures;

use futures::executor::ThreadPool;
use futures::prelude::*;
use futures::task::Context;
use std::{thread, time::Duration};

struct SendThree {
    firstTime: bool,
}

impl Future for SendThree {
    type Item = u32;
    type Error = Never;

    fn poll(&mut self, ctx: &mut Context) -> Result<Async<Self::Item>, Never> {
        if self.firstTime {
            self.firstTime = false;
            thread::spawn(move || {
                thread::sleep(Duration::from_millis(10));
                ctx.waker().wake();
            });
            Ok(Async::Pending)
        } else {
            Ok(Async::Ready(3))
        }
    }
}

fn main() {
    let mut fut = SendThree { firstTime: true };
    let mut executor: ThreadPool = ThreadPool::new().unwrap();
    let result = executor.run(fut).unwrap();
    println!("{}", result);
}

детская площадка

Моя проблема в том, что переменная Context не Send, поэтому я не могу вызвать wake из другого потока:

error[E0277]: the trait bound `futures::executor::Executor: std::marker::Send` is not satisfied
  --> src/main.rs:19:13
   |
19 |             thread::spawn(move || {
   |             ^^^^^^^^^^^^^ `futures::executor::Executor` cannot be sent between threads safely
   |
   = help: the trait `std::marker::Send` is not implemented for `futures::executor::Executor`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&mut futures::executor::Executor`
   = note: required because it appears within the type `std::option::Option<&mut futures::executor::Executor>`
   = note: required because it appears within the type `futures::task::Context<'_>`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&mut futures::task::Context<'_>`
   = note: required because it appears within the type `[closure@src/main.rs:19:27: 22:14 ctx:&mut futures::task::Context<'_>]`
   = note: required by `std::thread::spawn`

Если я изменю код на это, он будет работать, но я могуthread::sleep без блокировки:

if self.firstTime {
    self.firstTime = false;
    ctx.waker().wake();
    Ok(Async::Pending)
}

Есть ли идиоматический способ реализовать это?

1 Ответ

0 голосов
/ 19 мая 2018

Хотя Context не может быть отправлено между потоками, Waker:

fn poll(&mut self, ctx: &mut Context) -> Result<Async<Self::Item>, Never> {
    if self.first_time {
        self.first_time = false;
        let waker = ctx.waker().clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_millis(10));
            waker.wake();
        });
        Ok(Async::Pending)
    } else {
        Ok(Async::Ready(3))
    }
}

Обратите внимание, что это действительно неэффективный способ реализации тайм-аутов.Вместо этого есть фьючерсные методы.

...