Skip to main content

Understanding thread pools through cats-effect

1 hour 

Follow along

Assuming you’re familiar with SBT, create a build.sbt with the following contents:

ThisBuild / scalaVersion := "3.0.2"
ThisBuild / libraryDependencies +=
  "org.typelevel" %% "cats-effect" % "3.3.2"

Enter the console with sbt console.

Copy the following setup code into the repl. This code sets up a few IORuntime variants for us to play with ⸺ you don’t need to understand it:

import cats.effect._
import cats.effect.unsafe._
import cats.effect.implicits._
import cats.implicits._

object Threading {

  val basicRuntime: IORuntime = IORuntime(
    compute = IORuntime.createDefaultBlockingExecutionContext("compute")._1,
    blocking = IORuntime.createDefaultBlockingExecutionContext("blocking")._1,
    scheduler = IORuntime.createDefaultScheduler()._1,
    shutdown = () => (),
    config = IORuntimeConfig()
  )

  def boundedRuntime(numThreads: Int): IORuntime = {
    lazy val lazyRuntime: IORuntime = {
      IORuntime(
        compute = IORuntime
          .createDefaultComputeThreadPool(lazyRuntime, numThreads, "compute")
          ._1,
        blocking =
          IORuntime.createDefaultBlockingExecutionContext("blocking")._1,
        scheduler = IORuntime.createDefaultScheduler()._1,
        shutdown = () => (),
        config = IORuntimeConfig()
      )
    }
    lazyRuntime
  }

  def time(work: IO[Unit]): IO[String] =
    work.timed.map {
      case (t, _) => s"The task took ${t.toSeconds} seconds."
    }
}
import Threading._

Finally, make sure your laptop is plugged in. We’ll likely need a fair amount of power.