问题
I have a slow future that blocks for 1 second before running to completion.
I've tried to use the join
combinator but the composite future my_app
executes the futures sequentially:
#![feature(pin, futures_api, arbitrary_self_types)]
extern crate futures; // v0.3
use futures::prelude::*;
use futures::task::Context;
use std::pin::PinMut;
use std::{thread, time};
use futures::executor::ThreadPoolBuilder;
struct SlowComputation {}
impl Future for SlowComputation {
type Output = ();
fn poll(self: PinMut<Self>, _cx: &mut Context) -> Poll<Self::Output> {
let millis = time::Duration::from_millis(1000);
thread::sleep(millis);
Poll::Ready(())
}
}
fn main() {
let fut1 = SlowComputation {};
let fut2 = SlowComputation {};
let my_app = fut1.join(fut2);
ThreadPoolBuilder::new()
.pool_size(5)
.create()
.expect("Failed to create threadpool")
.run(my_app);
}
Why does join
work like that? I expected the futures to be spawned on different threads.
What is the right way to obtain my goal?
Cargo.toml:
[dependencies]
futures-preview = "0.3.0-alfa.6"
Result:
$ time target/debug/futures03
real 0m2.004s
user 0m0.000s
sys 0m0.004s
回答1:
If you combine futures with join()
they'll be transformed into a single task, running on a single thread.
If the futures are well-behaved, they would run in parallel in an event-driven (asynchronous) manner. You would expect your application to sleep for 1 second.
But unfortunately the future you implemented is not well-behaved. It blocks the current thread for one second, disallowing any other work to be done during this time. Because the futures are run on the same thread, they cannot run at the same time. Your application will sleep for 2 seconds.
Note that if you change your example to the following, the futures will remain separate tasks and you can run them independently in parallel on your thread pool:
fn main() {
let fut1 = SlowComputation {};
let fut2 = SlowComputation {};
let mut pool = ThreadPoolBuilder::new()
.pool_size(5)
.create()
.expect("Failed to create threadpool");
pool.spawn(fut1);
pool.run(fut2);
}
Writing futures that block the main thread is highly discouraged and in a real application you should probably use timers provided by a library, for example tokio::timer::Delay or tokio::timer::timeout::Timeout.
来源:https://stackoverflow.com/questions/52313031/how-to-run-multiple-futures-that-call-threadsleep-in-parallel