scala.concurrent.Future.onSuccess在不同ExecutorService上的执行时间

时间:2017-01-05 10:29:11

标签: scala

我想控制ExecutionContext中的线程数。所以我创建了一个ThreadPoolExecutor实例,然后从中创建了ExecutionContext。

我创建了一些期货,并附上onSuccess回调。我期望每个Future工作完成后调用每个onSuccess回调。但我发现所有onSuccess回调都是在同一时间执行的。

import java.util.concurrent.{ Executors, ForkJoinPool }

import scala.concurrent.{ Await, ExecutionContext, Future }
import scala.concurrent.duration.Duration

object Main extends App {
  implicit val ec = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(2))
  // implicit val ec = ExecutionContext.fromExecutorService(new ForkJoinPool(2))

  val start = System.currentTimeMillis()

  val futures = for {
    i <- 1 to 10
  } yield Future[Int] {
    Thread.sleep(i * 1000)
    i
  }

  futures.foreach { f =>
    f.onSuccess { case i =>
      println(s"${i} Success. ${System.currentTimeMillis() - start}ms elapsed.")
    }
  }

  Await.ready(Future.sequence(futures.toList), Duration.Inf)
  ec.shutdown()
}

// ThreadPoolExecutor Result
// 1 Success. 25060ms elapsed.
// 2 Success. 25064ms elapsed.
// 3 Success. 25064ms elapsed.
// 4 Success. 25064ms elapsed.
// 5 Success. 25064ms elapsed.
// 6 Success. 25064ms elapsed.
// 7 Success. 25065ms elapsed.
// 8 Success. 25065ms elapsed.
// 9 Success. 25065ms elapsed.
// 10 Success. 30063ms elapsed.

// ForkJoinPool Result
// 1 Success. 1039ms elapsed.
// 2 Success. 2036ms elapsed.
// 3 Success. 4047ms elapsed.
// 4 Success. 6041ms elapsed.
// 5 Success. 12042ms elapsed.
// 6 Success. 12043ms elapsed.
// 7 Success. 25060ms elapsed.
// 8 Success. 25060ms elapsed.
// 9 Success. 25060ms elapsed.
// 10 Success. 30050ms elapsed.

上述结果分别同时打印。但是当我使用ForkJoinPool而不是ThreadPoolExecutor时,这个问题就会减轻。我是否误用了ExecutionContext和Future?

编辑:我发现当线程数少于期货数时就会出现问题。所以我编辑了上面的代码来重现问题并打印执行时间。

我认为即使线程数很小,也应该按时调用未来的回调......

1 个答案:

答案 0 :(得分:0)

我最终知道在所提供的ExecutionContext的线程上执行了Future回调(onComplete或onSuccess)。因此,如果池中没有空闲线程,则无法执行回调。 See scala.concurrent.Future

但我仍然不了解ForkJoinPool的行为。我需要研究一下。