未来的concurrent.blocking在某些情况下无法正常工作

时间:2018-02-25 06:32:05

标签: scala akka future

帮助解释scala future的2个现象(在代码4& code5中加粗),谢谢。

代码1

package com.tst
import akka.actor.{Actor, ActorSystem, Props}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

class MyActor extends Actor {
  def receive = {
    case _ =>
      for (i <- 1 to 6) {
        Future {
          println("start")
          Thread.sleep(30000)
          println("end")
        }
      }
  }
}

object Test extends App {
  val system = ActorSystem()
  val myActor = system.actorOf(Props[MyActor])
  myActor ! 'msg
}

对于code1,因为我的cpu核心是4,所以在最初的30秒,我们只能看到4 start打印,对我来说没问题。 (如果你的cpu有更多核心,例如8核心,你可以将循环从6改为10来重现我的问题)

代码2

package com.tst
import akka.actor.{Actor, ActorSystem, Props}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future, blocking}

class MyActor extends Actor {
  def receive = {
    case _ =>
      for (i <- 1 to 6) {
        Future {
          blocking {
            println("start")
            Thread.sleep(30000)
            println("end")
          }
        }
      }
  }
}

object Test extends App {
  val system = ActorSystem()
  val myActor = system.actorOf(Props[MyActor])
  myActor ! 'msg
}

对于code2,当添加blocking时,会使用其他线程,因此我们最初可以看到6 start打印,对我来说没问题。

CODE3

package com.tst
import akka.actor.{Actor, ActorSystem, Props}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Future, blocking}

class MyActor extends Actor {
  def receive = {
    case _ =>
      for (i <- 1 to 6) {
        Future {
          blocking { // lineA
            println("startpre")
            Thread.sleep(30000)
            println("endpre")
          }
        }
      }

      Thread.sleep(2000)

      for (i <- 1 to 6) {
        println("+")
        Future {
          blocking { // lineB
            println("start")
            Thread.sleep(30000)
            println("end")
          }
        }
      }
  }
}

object Test extends App {
  val system = ActorSystem()
  val myActor = system.actorOf(Props[MyActor])
  myActor ! 'msg
}

对于code3,我们可以看到6 startpre&amp; 6 start打印最初30秒,对我来说没问题。

码4

只需删除code3中的lineA,输出为:

startpre
startpre
startpre
startpre
+
+
+
+
+
+

这是我的第一个问题:为什么我可以在最初的30秒内看到4 startpre?为什么lineB中的blocking不起作用?根据我的理解,我还应该看到6 start

代码4

只需删除code3 for code3,如果在code4中删除它,请记得取消删除lineA,输出为:

startpre
startpre
startpre
startpre
startpre
startpre
+
+
+
+
+
+
start

这是我的第二个问题:这里有1 start被看到,但是所有4个线程都已被占用,并且为lineA的Future启动了2个额外的线程,为什么还剩下一个线程for lineB打印1 start

1 个答案:

答案 0 :(得分:2)

Here我的观点很好。

将部分代码放在blocking通知执行上下文中,可能需要一些其他线程结果来完成此阻塞。因此,运行另一个线程来完成加速评估是合理的。

换句话说,在你的情况code4 4个线程忙于从第一个循环执行Futures,它们没有标记为blocking所以没有理由在池中添加另一个工作线程,所以,没有线程可以从第二个循环中执行任何新的Future

code5中,所有帖子都忙于Future标记为blocking。其他线程已启动,在没有Future的情况下从另一个循环中占用blocking,因此没有理由再添加一个线程。