I’m trying to reuse some module that uses monix.eval.Task for async tasks.
My project uses scala.concurrent.Future.
I'm trying to understand the best way to convert it to Future with the least amount of damage.
The easiest way is to use an additional thread pool:
import monix.eval.Task
import monix.execution.Scheduler.Implicits.global
import scala.concurrent.Future
// Create a Monix Task
val monixTask: Task[String] = Task("Hello, Monix!")
// Convert the Task to a Future using toFuture
val scalaFuture: Future[String] = monixTask.toFuture
But I don't fully understand the performance implications.
- I already have
scala.concurrent.ExecutionContextdefined in the project. What are the implications of adding the globalmonix.execution.Scheduler? - Where the tasks will actually be computed? With
ExecutionContextorScheduler? I'm guessing it queue up onScheduler, have a small overhead of conversion, and then run onExecutionContext?
The given module simply uses Task.deferFuture on all the Future he receives.
The async tasks are IO tasks, having 300k~600k rpm.
Monix's default Scheduler delegates to the Scala default ExecutionContext, so if you were trying to avoid using that EC, you should define your own Scheduler instance that uses your custom EC. The Scheduler companion has a handful of
applymethods defined for this purpose.A Scheduler uses a
ScheduledExecutorServicefor scheduling tasks, and anExecutionContextfor running the tasks. So if you pass your custom ExecutionContext to theScheduler.apply, your tasks will run there.A note about interop between
TaskandFuture: aTaskis lazy by nature. Constructing one does not run it. So when wrapping a Future-returning expression as aTask, thedeferFuturetakes the expression in call-by-name style, so that the Future will not actually be constructed and started until that Task is told to run.Since you mentioned the Tasks contain IO (I'm assuming you mean in the "I/O" sense, not
cats.effect.IO), it might be appropriate to set up a separate dedicated thread pool (ExecutionContext) for performing IO-bound operations, so those don't block your CPU-bound "compute" threads. SeeScheduler.ioas a starting point for that.