Erik Kaplun
Erik Kaplun

Reputation: 38217

Is there a way to get a non-global clone of scala.concurrent.ExecutionContext.global?

I'm looking for a non-global instance of the ForkJoinPool so that I'd get all the great default parallelism and execution semantics of the global instance with the ability to control the life cycle of the pool.

I peeked into the source code of scala.concurrent and scala.concurrent.impl, and, sadly, it looks like all of the code that's creating the default instance is private[scala.concurrent], and there's no indirect way to call the code either.

I can only get a fresh instance of the ExecutionContext with default settings using ExecutionContext.fromExecutor(null), but there's no way to grab ahold of the underlying ForkJoinPool. Nor is there a way to shut down an ExecutionContext directly.

Am I doing something esoteric that I shouldn't be doing? Because to me it seems like a natural thing to want: default semantics/configuration of something without the global'ness of it.

Upvotes: 3

Views: 449

Answers (2)

som-snytt
som-snytt

Reputation: 39577

It's not a question of access but of shape. The tail of the elephant:

scala> type ECI = { def createExecutorService: ExecutorService }
defined type alias ECI

scala> val fjp = ExecutionContext.global.asInstanceOf[ECI].createExecutorService
fjp: java.util.concurrent.ExecutorService = scala.concurrent.forkjoin.ForkJoinPool@606dff1[Running, parallelism = 8, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]

or shapelessly:

scala> import shapeless.syntax.typeable._
import shapeless.syntax.typeable._

scala> val fjp = concurrent.ExecutionContext.global.cast[ECI] map (_.createExecutorService) getOrElse ???
fcp: java.util.concurrent.ExecutorService = scala.concurrent.forkjoin.ForkJoinPool@45c26421[Running, parallelism = 8, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]

and then

scala> val eces = ExecutionContext fromExecutorService fjp
eces: scala.concurrent.ExecutionContextExecutorService = scala.concurrent.impl.ExecutionContextImpl$$anon$1@1df3794c

scala> eces.shutdown

Upvotes: 3

Urist McDev
Urist McDev

Reputation: 508

The good thing about private[path.to.package] is that you can work around it simply by pretending to be inside that package:

package scala.concurrent

import java.util.concurrent.Executor

object Foo {
  implicit lazy val myGlobalExecutionContext: ExecutionContextExecutor =
    impl.ExecutionContextImpl.fromExecutor(null: Executor)
}

However, be advised that if you do this, you are not in the realm of public API anymore and will have to deal with certain incompatibilities when you change the scala version.

Upvotes: 3

Related Questions