如何并行执行期货的未来并等待它们完成(并行运行)

时间:2018-04-18 09:15:14

标签: scala concurrency scala-collections

我想执行“流”,其中每个流并行执行。每个流本身使用期货执行操作:

def doFlow(...): Seq[Future[Something]] = {
  (1 to 10) map {
   Future {
      Something(...)
   }
  }
}


val sequence: Seq[Seq[Future[Something]]] = (1 to 10) map {
  iter => doFlow(...)
}

// now I want to wait for all of them to complete:

val flat: Seq[Future[Something]] = sequence.flatten

val futureSeq = Future.sequence(flat)

futureSeq.onComplete {
   ...
   case Success(val) => {...}
}

我正在打印完成日志,我发现它们按顺序运行而不是像我想要的那样并行运行

=======================
First started at Wed Apr 18 12:02:22 IDT 2018
Last ended at Wed Apr 18 12:02:28 IDT 2018
Took 4.815 seconds
=======================
First started at Wed Apr 18 12:02:28 IDT 2018
Last ended at Wed Apr 18 12:02:35 IDT 2018
Took 4.335 seconds
=======================
First started at Wed Apr 18 12:02:35 IDT 2018
Last ended at Wed Apr 18 12:02:41 IDT 2018
Took 3.83 seconds
...
...

2 个答案:

答案 0 :(得分:2)

在我的机器上运行:

  import ExecutionContext.Implicits.global

  def doFlow(chunk: Int): Seq[Future[Int]] = {
    (1 to 5) map { i =>
      Future {
        println(s"--> chunk $chunk idx $i")
        Thread.sleep(1000)
        println(s"<-- chunk $chunk idx $i")
        0
      }
    }
  }


  val sequence: Seq[Seq[Future[Int]]] = (1 to 5) map {
    iter => doFlow(iter)
  }
  val flat: Seq[Future[Int]] = sequence.flatten
  val futureSeq = Future.sequence(flat)
  Await.ready(futureSeq, scala.concurrent.duration.Duration.Inf)

输出样本:

--> chunk 1 idx 2

--> chunk 1 idx 4

--> chunk 1 idx 1

--> chunk 1 idx 3

--> chunk 2 idx 1

--> chunk 1 idx 5

--> chunk 2 idx 3

--> chunk 2 idx 2

<-- chunk 1 idx 2

<-- chunk 2 idx 1

<-- chunk 1 idx 3

--> chunk 2 idx 5

--> chunk 3 idx 1

<-- chunk 1 idx 1

<-- chunk 1 idx 5

<-- chunk 1 idx 4

--> chunk 3 idx 3

--> chunk 2 idx 4

一次处理8个任务。 你在Something内有任何可以引入阻塞的内部同步吗?

答案 1 :(得分:0)

Future.sequence(xs.map { x => futureY })

是要走的路。

但是,如果您的未来立即完成,或者ExecutorContext一次只处理其中一个,那么它们将是有效的顺序。

你的期货确实需要时间来执行,所以我会调查ExecutionContext。 ExecutionContext.Implicits.global使用尽可能多的主机拥有CPU(因此,单个核心机器将具有1个线程的ExecutorService)。

为SingleThreadExecutor定义ExecutorContext也会导致顺序运行。

然后还有可能在Future中阻塞。或追查错误的事情。

要了解更多信息,我们必须查看Something(...)的作用以及您使用的ExecutorContext是什么。