2

Suppose I want to know how many threads there are in a given ExecutionContext.
So I am writing a function like this

def count(implicit ec: ExecutionContext): Int = {
  val promise = Promise[Unit]
  val counter = new AtomicInteger(0)
  for (_ <- 0 to 1000) Future {
    counter.getAndIncrement()
    Await.ready(promise.future, Duration.Inf)
  }
  val result = counter.get()
  promise.success(())
  result
}

It does not work for ExecutionContext.global at least so I changed the implementation:

def count(implicit ec: ExecutionContext): Int = {
  val barrier = new CyclicBarrier(1000)
  var isReset = false
  for (_ <- 0 to 1000) Future { if (!isReset) barrier.await() }
  val result = barrier.getNumberWaiting
  barrier.reset()

  // make all futures complete and release all threads to allow JVM to exit
  isReset = true 

 result
}

It works but I wonder

  • why the first implementation does not work;
  • how to improve the "barrier" implementation (e.g. get rid of the isReset) ;
  • what the best way to count threads in an ExecutionContext is.
Michael
  • 41,026
  • 70
  • 193
  • 341
  • 1
    I believe it would be easier to use reflection or casting to access the underlying java executor which has a available threads getter. I did that once debugging a weird error but I do not have the anymore and I am in a cellphone so I would be very hard to type it again, but I hope the advice helps. Look at the source code in the Scala github that was what gave me the idea. – Luis Miguel Mejía Suárez May 09 '21 at 18:31

1 Answers1

2

Try casting to particular executor, for example

implicit val ec = scala.concurrent.ExecutionContext.Implicits.global
Future(42)
ec.asInstanceOf[java.util.concurrent.ForkJoinPool].getPoolSize // : Int = 1
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • Thanks. What about other questions ? Why does not the first "await" implementation work ? Looks like `global` is aware of `Await.ready` and adds new threads. – Michael May 10 '21 at 07:35
  • 2
    Michael, because Await uses managed blocking to notify the pool that it needs to spin up more threads to avoid starvation. Same goes if you had used `blocking { … }`. – Viktor Klang May 10 '21 at 09:06
  • @ViktorKlang Thanks. I should have checked the sources. Found `blocking` in https://github.com/scala/scala/blob/2.12.x/src/library/scala/concurrent/package.scala#L196 – Michael May 10 '21 at 09:20