未来{封闭{创建新的未来{}}} - 嵌套的期货会阻止父母一个

时间:2015-08-23 20:15:09

标签: multithreading scala nested future blocking

我试图用实际代码模拟我的情况。

用例很简单: 有:

 Future {blocking { 
   // in there it calls nested futures    
 }}

更详细(全局执行上下文用作父项,但有些人试图将separete用于子项):

object ExContexts {
  val main = scala.concurrent.ExecutionContext.Implicits.global
  val ecChildren = scala.concurrent.ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))
}

object NestedFutures2 extends App {

  import scala.concurrent.ExecutionContext.Implicits.global

  val cores = Runtime.getRuntime.availableProcessors

  val works = parentWork(ExContexts.main) // main EC

  val result1: Seq[Seq[Future[String]]] = Await.result(Future.sequence(works), Duration.Inf)
  println("parents are done their work")
  val result2: Seq[String] = Await.result(Future.sequence(result1.flatten), Duration.Inf)

  // ---

  def parentWork(ex:ExecutionContext): Seq[Future[Seq[Future[String]]]] = {

    val works: Seq[Future[Seq[Future[String]]]] =

      (1 to cores * 2) map { x =>

        Future {
          blocking { // will create new thread/place if needed

            val parentName = Thread.currentThread.getName

            println("parent: " + parentName + " started an action")

            val playFutureOutcomes: Seq[Future[String]] = (1 to 10) map {stuffId =>
              childPlay(parentName = parentName)(ExContexts.ecChildren)
            }

            Thread.sleep(1000)

            println(s"[${timeStamp()}] parent: " + parentName + " has finished the action")

            playFutureOutcomes
          }
        }
      }
    works
  }

  def childPlay(parentName:String)(ex:ExecutionContext):Future[String] = {
    Future {
      Thread.sleep(2000) // two seconds play session
      val threadName = Thread.currentThread.getName
      // log
      println("child: " + threadName + " of " + parentName + " parent")
      Thread.currentThread.getName
    }
  }

  def timeStamp(pattern:String = "ss:mm : hh"): String = {
    val fmt = DateTimeFormat.forPattern(pattern)
    fmt.print(DateTime.now)
  }


}

从输出(8个parrent期货中的5个完成)我看到孩子们利用父母线程...:

[01:31 : 05] parent: ForkJoinPool-1-worker-5 has finished the action
[01:31 : 05] parent: ForkJoinPool-1-worker-11 has finished the action
[01:31 : 05] parent: ForkJoinPool-1-worker-1 has finished the action
[01:31 : 05] parent: ForkJoinPool-1-worker-3 has finished the action
[01:31 : 05] parent: ForkJoinPool-1-worker-7 has finished the action
child: ForkJoinPool-1-worker-13 of ForkJoinPool-1-worker-1 parent
child: ForkJoinPool-1-worker-5 of ForkJoinPool-1-worker-5 parent
child: ForkJoinPool-1-worker-1 of ForkJoinPool-1-worker-1 parent
child: ForkJoinPool-1-worker-11 of ForkJoinPool-1-worker-11 parent
child: ForkJoinPool-1-worker-3 of ForkJoinPool-1-worker-3 parent
child: ForkJoinPool-1-worker-7 of ForkJoinPool-1-worker-7 parent
child: ForkJoinPool-1-worker-13 of ForkJoinPool-1-worker-11 parent
...

我希望父母一个人能在1秒钟内完成工作,因为如果我们没有孩子的话。此外,我希望看到两个连接池而不是一个。

问:获得它的建议是什么?

更新 我想这是基于Implicit.glocal构建的Join-Pool。所有嵌套的Furue都将连接到一个池?

// What (I think) I see is that if we have 'global' execution context as parent/main,
// then whatever we pass as execution context to the child Future still will use global context
// and still will be using ONE connection pool.
// And then therefore wll have performance problem if children do not use 'blocking' -
// parents will be stuck in cores-long connection pool

// So: Children will 'inherit' execution context, but not 'blocking'
// and as children connected/joined to the execution context the parents will not be able to do
// anything about it but wait for the free space in the pool (when child is done)
// new additional threads will not be creating for the next parent because (i guess)
// Global execution context will not see the reason of/for it.

// Like a snapshot of the moment of time:
// Connection Pool: [ch1, ch2, ch3, p1]

// It things:Ok there is one parent (p1) in the pool if one more parent
// future will come I create for it new thread it the pool.
// But because we have more joined children than parents in the list
// the moment when Global ex context can help parent will never come.

如果我希望父母独立于childrent,反之亦然,那么我是否应该使用全局上下文? (有趣的是,互联网上有多少人只玩全球。)

说我知道ma app有20 000个客户端,每个客户端总是进行1-100秒长的操作(op1-> op1.op1)。然后我就可以将一个执行上下文用于20 000个连接池(最大值)。和所有类型的长期运行所需的执行上下文一样多(父级 - >子级,其中子级未向父级报告)。说:printingExConlogExConreadStufExConwriteStuffExCon

但是,如果我知道一个oparation应该包括anoter one并且他们可能加入然后(仅)我可以使用那个全局Ex上下文?

否则,如果我使用全局 ex上下文作为人工上下文 - 所有人都会加入它并且我最终会遇到性能问题,我在本周日开始时解释了这个问题。

更新  我浪费了很多时间试图理解为什么修复版本('ex'传递给childPlay的Future {}(ex)产生的输出忽略了睡眠并且在许多其他情况下表现得很好。问题是修复而不是运行/在IntellyJIDEA 14中构建(按CTRL-SHIFT + F10)我构建它有机会运行..

0 个答案:

没有答案