~zainab/blog

0034c2f439242deeffa91ed827f2fd833882e006 — zainab-ali 6 months ago f532449
Generate snippets for IORuntime post locally
2 files changed, 373 insertions(+), 4 deletions(-)

M nix/mdoc.bash
A src/chapters/2022-02-12-cats-effect-ioruntime/snippets.out.md
M nix/mdoc.bash => nix/mdoc.bash +7 -4
@@ 14,7 14,10 @@ timeout 1m cs launch org.scalameta:mdoc_3:2.3.1 -- \
   --in src/chapters/fs2/snippets.md \
   --out src/chapters/fs2/snippets.out.md || true

timeout 5m cs launch org.scalameta:mdoc_3:2.3.1 -- \
	 --classpath $catseffect \
	 --in src/chapters/2022-02-12-cats-effect-ioruntime/snippets.md \
	 --out src/chapters/2022-02-12-cats-effect-ioruntime/snippets.out.md || true
# FIXME: This post uses run-specific details, such as the number of CPUs on its
# host and the time taken to run. For now, we don't run it on the CI machine and
# generate it locally instead.
# timeout 5m cs launch org.scalameta:mdoc_3:2.3.1 -- \
# 	 --classpath $catseffect \
# 	 --in src/chapters/2022-02-12-cats-effect-ioruntime/snippets.md \
# 	 --out src/chapters/2022-02-12-cats-effect-ioruntime/snippets.out.md || true

A src/chapters/2022-02-12-cats-effect-ioruntime/snippets.out.md => src/chapters/2022-02-12-cats-effect-ioruntime/snippets.out.md +366 -0
@@ 0,0 1,366 @@
# sbt

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

# imports
```scala
import $ivy.`org.typelevel::cats-effect:3.3.2`
```

# setup

```scala
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._
```

# snooze

```scala
val snooze: IO[Unit] = IO(Thread.sleep(2000L))
```

# run-snooze-no-runtime

```scala
time(snooze).unsafeRunSync()
// error:
// Could not find an implicit IORuntime.
// 
// Instead of calling unsafe methods directly, consider using cats.effect.IOApp, which
// runs your IO. If integrating with non-functional code or experimenting in a REPL / Worksheet,
// add the following import:
// 
// import cats.effect.unsafe.implicits.global
// 
// Alternatively, you can create an explicit IORuntime value and put it in implicit scope.
// This may be useful if you have a pre-existing fixed thread pool and/or scheduler which you
// wish to use to execute IO programs. Please be sure to review thread pool best practices to
// avoid unintentionally degrading your application performance.
// 
// val betterSnoozeAndCompute: IO[Unit] =
//                                       ^
```

# run-snooze

```scala
time(snooze).unsafeRunSync()(basicRuntime)
// res1: String = "The task took 2 seconds."
```

# snooze-list

```scala
val snoozes: List[IO[Unit]] = List(snooze, snooze)
```

# snooze-parallel

```scala
val parallelSnoozes: IO[Unit] = snoozes.parSequence.void
```

# snooze-parallel-run

```scala
time(parallelSnoozes).unsafeRunSync()(basicRuntime)
// res2: String = "The task took 2 seconds."
```

# snooze-parallel-thousand

```scala
val lotsOfSnoozes = List.fill(1000)(snooze).parSequence.void
```



# snooze-parallel-thousand-run

```scala
time(lotsOfSnoozes).unsafeRunSync()(basicRuntime)
// res3: String = "The task took 2 seconds."
```

# factorial

```scala
val factorial: IO[Unit] = {
  @scala.annotation.tailrec
  def go(n: Long, total: Long): Long =
    if (n > 0) go(n - 1, total * n - 1) else total
  IO(go(2000000000L, 1)).void
}
```

# factorial-run

```scala
time(factorial).unsafeRunSync()(basicRuntime)
// res4: String = "The task took 2 seconds."
```

# factorial-io-parallelized

```scala
val factorials: IO[Unit] = List.fill(10)(factorial).parSequence.void
```

# factorial-io-parallelized-run

```scala
time(factorials).unsafeRunSync()(basicRuntime)
// res5: String = "The task took 3 seconds."
```

# runtime-available-processors

```scala
val numProcessors = Runtime.getRuntime().availableProcessors()
// numProcessors: Int = 8
```

# factorial-io-parallelized-time-each


```scala
val timedFactorial: IO[String] = time(factorial)
val timedFactorials: IO[List[String]] =
  List.fill(20)(timedFactorial).parSequence
```

# factorial-io-parallelized-time-each-run

```scala
timedFactorials.unsafeRunSync()(basicRuntime)
// res6: List[String] = List(
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 4 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds."
// )
```

# factorial-bounded-threadpool

```scala
time(factorials).unsafeRunSync()(boundedRuntime(2))
// res7: String = "The task took 12 seconds."
```

# factorial-time-bounded-threadpool

```scala
timedFactorials.unsafeRunSync()(boundedRuntime(2))
// res8: List[String] = List(
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds."
// )
```

# factorial-time-bounded-threadpool-20

```scala
timedFactorials.unsafeRunSync()(boundedRuntime(20))
// res9: List[String] = List(
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 4 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 5 seconds.",
//   "The task took 5 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds.",
//   "The task took 6 seconds."
// )
```

# factorial-time-bounded-threadpool-available

```scala
timedFactorials.unsafeRunSync()(boundedRuntime(numProcessors))
// res10: List[String] = List(
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds.",
//   "The task took 2 seconds."
// )
```

# snooze-10

```scala
val tenSnoozes: IO[Unit] = List.fill(10)(snooze).parSequence.void
```

# snooze-10-run

```scala
time(tenSnoozes).unsafeRunSync()(boundedRuntime(numProcessors))
// res11: String = "The task took 4 seconds."
```


# combined

```scala
val snoozeAndCompute: IO[Unit] = 
  List(factorials, tenSnoozes).parSequence.void
```

# combined-run

```scala
time(snoozeAndCompute).unsafeRunSync()(boundedRuntime(numProcessors))
// res12: String = "The task took 6 seconds."
```

# setup-bounded-runtime

```scala
def boundedRuntime(numThreads: Int): IORuntime = 
  IORuntime(
    compute = IORuntime.createDefaultComputeThreadPool(numThreads),
    blocking = IORuntime.createDefaultBlockingExecutionContext()
  )
```

# compute-threadpool

```scala
boundedRuntime(numProcessors).compute
// res13: ExecutionContext = cats.effect.unsafe.WorkStealingThreadPool@4da4ceec
```

# better-snooze

```scala
val betterSnooze: IO[Unit] = IO.blocking(Thread.sleep(2000L))
val tenBetterSnoozes: IO[Unit] =
  List.fill(10)(betterSnooze).parSequence.void
```

# better-snooze-run

```scala
time(tenBetterSnoozes).unsafeRunSync()(boundedRuntime(numProcessors))
// res14: String = "The task took 2 seconds."
```

# combined-blocking

```scala
val betterSnoozeAndCompute: IO[Unit] =
  List(factorials, tenBetterSnoozes).parSequence.void
```


# combined-blocking-run

```scala
time(betterSnoozeAndCompute).unsafeRunSync()(
  boundedRuntime(numProcessors)
  )
// res15: String = "The task took 5 seconds."
```