The concurrent.blocking in future not work as expected in some scenario
Asked Answered
S

1

0

Help to explain 2 phenomenon for scala future(Bold in code4 & code5), thanks.

Code1

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
}

For code1, as my cpu core is 4, so at first 30 seconds, we can just see 4 start print, no problem for me. (If your cpu has more cores, e.g. 8 core, you may change the loop from 6 to 10 to reproduce my question)

Code2

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
}

For code2, as blocking is added, additional threads was employed, so we can see 6 start print at first, no problem for me.

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
}

For code3, we can see 6 startpre & 6 start print at first 30 seconds, no problem for me.

code4

Just delete lineA in code3, the output is:

startpre
startpre
startpre
startpre
+
+
+
+
+
+

This is my first question: why I can just see 4 startpre at first 30 seconds? Why blocking in lineB not work here? With my understanding, I should also see 6 start

code5

Just delete lineB for code3, remember to undelete lineA if you delete it in code4, the output is:

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

This is my second question: here there is 1 start be seen, but all 4 threads has been occupied, and 2 additional thread was launched for lineA's Future, why still one thread left for lineB to print 1 start?

Sloat answered 25/2, 2018 at 6:32 Comment(0)
X
2

Here it is described good at my point of view.

Placing part of code in blocking notify execution context that some other thread result could be required to complete this blocking. So could be reasonable to run another thread to complete speedup evaluation.

In other words in your case code4 4 threads are busy with execution of Futures from first loop, they are not marked as blocking so no reason to add another working thread in pool, and, so, no thread to execute any new Future from second loop.

In code5 all threads are busy with Future marked as blocking. Additional thread was started, occupied with Future from another loop without blocking so no reason to add one more thread.

Xylem answered 25/2, 2018 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.