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

scala.concurrent.Future.onSuccess在不同ExecutorService上的执行时间,scala,future,executioncontext,Scala,Future,Executioncontext,我想控制ExecutionContext中的线程数。所以我创建了ThreadPoolExecutor的一个实例,然后从中创建了ExecutionContext 我创建了一些期货,并附上了成功回调。我希望在以后的每项工作完成时都会调用onSuccess回调。但我发现所有onSuccess回调都是同时执行的 import java.util.concurrent.{ Executors, ForkJoinPool } import scala.concurrent.{ Await, Executi

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

我创建了一些期货,并附上了成功回调。我希望在以后的每项工作完成时都会调用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.
import java.util.concurrent.{Executors,ForkJoinPool}
导入scala.concurrent.{Await,ExecutionContext,Future}
导入scala.concurrent.duration.duration
对象主应用程序{
隐式val ec=ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(2))
//隐式val ec=ExecutionContext.fromExecutorService(新ForkJoinPool(2))
val start=System.currentTimeMillis()
val期货=为{
我
f、 onSuccess{案例i=>
println(s“${i}成功。${System.currentTimeMillis()-start}毫秒已过。”)
}
}
wait.ready(Future.sequence(futures.toList),Duration.Inf)
ec.关闭()
}
//线程池执行器结果
//1.成功。25060毫秒过去了。
//2.成功。25064毫秒过去了。
//3.成功。25064毫秒过去了。
//4.成功。25064毫秒过去了。
//5.成功。25064毫秒过去了。
//6.成功。25064毫秒过去了。
//7.成功。25065毫秒过去了。
//8.成功。25065毫秒过去了。
//9.成功。25065毫秒过去了。
//10.成功。30063毫秒过去了。
//ForkJoinPool结果
//1.成功。1039毫秒过去了。
//2.成功。2036毫秒过去了。
//3.成功。4047毫秒过去了。
//4.成功。6041毫秒过去了。
//5.成功。12042毫秒过去了。
//6.成功。12043毫秒过去了。
//7.成功。25060毫秒过去了。
//8.成功。25060毫秒过去了。
//9.成功。25060毫秒过去了。
//10.成功。30050毫秒过去了。
上述结果是同时打印的,而不是分别打印的。但当我使用ForkJoinPool而不是ThreadPoolExecutor时,这个问题得到了缓解。我是否误用了ExecutionContext和Future

编辑:我发现问题发生在线程数小于未来线程数时。所以我编辑了上面的代码来重现问题并打印执行时间


我认为未来的回调应该及时调用,即使线程数量很小……

我最终知道未来的回调(onComplete或onSuccess)是在提供的ExecutionContext的线程上执行的。因此,如果池中没有空闲线程,则无法执行回调。


但我仍然不理解ForkJoinPool的行为。我需要对此进行研究。

您需要发布您执行的确切代码。您粘贴的内容不完整,无法生成您描述的输出。事实上,对我来说,一切都像你期望的那样,而不是像你看到的那样。我只是编辑了这个问题。当线程数小于未来数时会出现问题…是否希望/需要将每个未来标记为
阻塞
,根据?否。我希望在未来完成时执行onSuccess回调。
ForkJoinPool
默认使用2*(CPU逻辑核心)线程。用相同的数字替换
nThreads
,使用
FixedThreadPool
将得到相同的结果。