Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unclear how to use CurrentThread and a "main future" #697

Closed
alexcrichton opened this issue Jan 8, 2018 · 5 comments
Closed

Unclear how to use CurrentThread and a "main future" #697

alexcrichton opened this issue Jan 8, 2018 · 5 comments

Comments

@alexcrichton
Copy link
Member

A typical pattern I've seen with tokio-core is to do something like:

let srv = ...;

handle.spawn(another_future);
handle.spawn(another_future2);
// ...

let result = core.run(srv);

// work with `result`

The Handle::spawn functionality is getting folded into CurrentThread but unfortunately I'm not sure how to recover the let result = core.run(srv) functionality from CurrentThread. Currently the closures in CurrentThread both return a bare R, the value returned by the closure, and the future::blocking module doesn't allow usage of CurrentThread. As a result, I don't think it's currently easily possible to construct a server like this, where you've got one "main future" you're interested in and it may spawn (or already have spawned) some sub-futures it was interested in.

The current state of tokio-rs/tokio-rfcs#3 solves this use case with:

pub fn block_on_all<F: Future>(f: F)  -> Result<F::Item, F::Error>;

and the RFC's current text could be tweaked a bit to accommodate an initialization closure as well:

pub fn block_with_init<F, R>(f: F) -> Result<R::Item, R::Error> 
    where F: FnOnce(&Enter) -> R,
          R: IntoFuture;
@carllerche
Copy link
Member

Similar to #698.

My impression based on confusion that has been encountered is that your initial example is an anti-pattern. The primary hazard is that another_future and another_future2 are spawned onto the executor, then the executor is run until srv completes, yielding the value back. At this point, the executor does not run anymore and another_future and another_future2 will be stalled.

block_on_all as it was proposed is an attempt to solve this. As described in the RFC, the supplied future is driven to completion, then the block_with_init function blocks until all spawned futures complete (i.e. to quiescence). The issue being that, until these futures complete, you cannot process the result. This seems like a hazard to me.

So, the way I see it, there are two scenarios:

  1. You have a single root future that you want to drive to completion and get the result immediately once it is ready.
  2. You have a set of futures you want to manage concurrently on a single thread.

In the first case, the answer is to use blocking::future. In the second, the answer is to spawn a bunch of futures onto CurrentThread, all of which are peers, and wait for them all to complete.

So, in your case, you would process the result in an and_then block and be done with it.

It may be that there really is a solid argument to add a way to block the thread for a single future while other tasks are also sharing the executor, unblocking when the "most important" future is ready. I would like to understand what this argument would be before trying to formalize a solution for it.

@alexcrichton
Copy link
Member Author

I think discussion is effectively continuing on #699 now.

@carllerche
Copy link
Member

#699 has merged, but there still is an open question, though I think it is the same as #698.

@alexcrichton
Copy link
Member Author

The block_on in #698 I believe would close this issue as well, yes.

@aturon
Copy link
Member

aturon commented Feb 12, 2018

I'm closing this in favor of the executor RFC.

@aturon aturon closed this as completed Feb 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants