Futures-rs: Doc/tutorial: how to consume futures and check for completion?

Created on 16 Nov 2016  路  14Comments  路  Source: rust-lang/futures-rs

I've used a lot Java futures in Java code, and recently I started trying out these Rust futures in a Rust library.

I was reading the documentation and tutorial (https://github.com/alexcrichton/futures-rs/blob/master/TUTORIAL.md), however I couldn't figure out something basic like, how to check if a future has completed or not.

The tutorial starts with a lot of examples on how to use combinators on futures. It also has an example on how to create a concrete future (Oneshot), and the various ways to return futures. But nowhere is there an example or explanation on how to check for completion, or wait for the future to complete.

poll is mentioned which at first seems what one would use, however poll needs to be run on a Task, and again, it's not clear how this is done. The section on tasks (https://github.com/alexcrichton/futures-rs/blob/master/TUTORIAL.md#task-and-future) does not explain this properly - it mentions spawn but all those mentions reference other crates like tokio-core spawn or CpuPool spawn. Does it mean we need to use one of those crates too?

However, even looking at CpuPool::spawn, that also returns a Future... so that means you're back at the start: you can't use poll, because you still have no task?

Eventually I found the Future::wait method which seems to work for waiting for the future completion. However, I still didn't figure out how to check for completion status.

docs

Most helpful comment

I took a quick look at https://tokio.rs/docs/going-deeper/futures-model/ , but I was wasn't able to understand it with just a quick look. I guess I would have to study it in more detail and at length, (unfortunately don't have the time for that at the moment).

But... all I wanted to know (regarding this ticket) was how to do in Rust the Java equivalent of checking Future#isDone() ... It doesn't seem to be I would need to study Rust's Future paradigm in such detail - but maybe I'm wrong? Maybe the way Futures work in Rust don't allow then to easily be checked for completion? (perhaps due to ownership issues, the state machine, etc.? - I don't really grok it ATM)

In other words, could an API like Future#isDone() be implemented for Rust's Future trait, or would that not make sense?

All 14 comments

Thanks for the report! The docs definitely need to be bolstered in this area to help out with these pieces.

To answer your questions, though, it's important to remember that Rust futures are pretty different than Java futures. For example "poll for completion" doesn't always make sense outside of a task itself because part of polling is doing more work on the future itself (e.g. the poll method). In the strictest sense, though:

  • To block waiting for a future to complete, yes Future::wait is the primary entry point.
  • To check whether a future is completed, you can call Future::poll inside of a task
  • Outside of a task, to check if a future is completed, it has to be spawned somehow. This can be accomplished via task::spawn which then allows you to call poll_future. The argument here is how to get notified when you should call poll again.

Does that make sense?

Outside of a task, to check if a future is completed, it has to be spawned somehow. This can be accomplished via task::spawn which then allows you to call poll_future. The argument here is how to get notified when you should call poll again.

Spawn::poll_future takes an Arc<Unpark> argument... what is that, and how do I get one? I've read the doc of Spawn and Unpark, but I still don't quite get it...

Ah yeah sure, Arc<Unpark> is actually a trait object with the Unpark trait. That object will receive notifications (calls to the unpark method) when the future needs to get polled again. We don't currently have any canned implementations of Unpark but there's some sample implementations in the test suite.

Ok, with that info I finally got the basic test code to work, thanks.

I've also read the the park/unpark doc for thread and now I get what it means, and understand a bit better how it relates to futures. (Thread park/unpark is sleep/interrupt in Java, so I didn't immediately recognize them just by name)

I'm leaving this ticket open since I think the tutorial needs some updating, but also the API: there should be a way of doing the above without the crate client having to implement a No-Op Unpark themselves.

Ok, sounds good to me!

Ok I think with https://tokio.rs we've covered bases like this, so I'm going to close this.

Ok I think with https://tokio.rs we've covered bases like this, so I'm going to close this.

Whoa, what? Are you sure? tokio is heavily focused on IO which is an additional layer on top of futures abstraction. There should be some basic documentation on this futures crate that doesn't require having to learn or install this many extraneous concepts like tokio, no?

Did you find the associated documentation not present ok tokio.rs?

I took a quick look at https://tokio.rs/docs/going-deeper/futures-model/ , but I was wasn't able to understand it with just a quick look. I guess I would have to study it in more detail and at length, (unfortunately don't have the time for that at the moment).

But... all I wanted to know (regarding this ticket) was how to do in Rust the Java equivalent of checking Future#isDone() ... It doesn't seem to be I would need to study Rust's Future paradigm in such detail - but maybe I'm wrong? Maybe the way Futures work in Rust don't allow then to easily be checked for completion? (perhaps due to ownership issues, the state machine, etc.? - I don't really grok it ATM)

In other words, could an API like Future#isDone() be implemented for Rust's Future trait, or would that not make sense?

In any case, I think it would be cleaner and simpler if the pages https://tokio.rs/docs/getting-started/futures/ and https://tokio.rs/docs/going-deeper/futures-model/ were in their own doc website, one just dedicated to futures, separated from tokio.rs.

Unfortunately isDone cannot be implemented for futures generally, all they provide is a poll function. An adapter can be written to check is_done in the same manner of .peekable().peek().is_some() (or something like that)

We're also considering poll_ready functions to specific implementations of futures & streams for which it makes sense.

@alexcrichton What do you think about this futures done checking?
https://github.com/DenisKolodin/future-control/blob/master/src/lib.rs#L66

I'm sure it works right to check execution success.
But I'm not sure that's correct to interrupt futures this way. Any thoughts?

thread_control source (if necessary):
https://github.com/DenisKolodin/thread-control/blob/master/src/lib.rs

thread-control crate is suitable to check or control futures directly and no wrapper needed.
The result is something like:

let (flag, control) = thread_control::make_pair();

let duration = Duration::from_secs(5);
let alive_checker = Interval::new(duration, &handle).unwrap()
    .and_then(move |value| {
        if flag.is_alive() {
            Ok(value)
        } else {
            Err(other("stream was interrupted by thread control!"))
        }
    });

thread::spawn(move || {
    // Any routine with `control.is_done()` checking
});

let managed_routine = alive_checker.select(mystream).for_each(|_| Ok(()));
core.run(managed_routine).unwrap();
Was this page helpful?
0 / 5 - 0 ratings