How to run multiple futures that call thread::sleep in parallel? [duplicate]

帅比萌擦擦* 提交于 2021-02-16 13:15:32

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!