Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Future of Typelevel Concurrency

The Future of Typelevel Concurrency

The Cats Effect and FS2 libraries power dozens of high level Scala libraries and provides the foundation for safe, functional concurrency. Cats Effect 3 & FS2 3 are on the verge of release, after 18 months of development, representing the largest change to the fundamentals since the initial 1.0 release. In this talk, we’ll look at what’s new and exciting in Cats Effect 3 and FS2 3.

Scala In The City, 11/25/2020

C9ab1175a6981a2f67ce8d08aa17c15a?s=128

Michael Pilquist

November 25, 2020
Tweet

Transcript

  1. The Future of Typelevel Concurrency Michael Pilquist // @mpilquist

  2. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 2.11 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  3. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) 2.11 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  4. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  5. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  6. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  7. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  8. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  9. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  10. 2 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  11. None
  12. 4 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  13. 4 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 1.0 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  14. 4 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 1.0 1.0 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  15. 4 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 1.0 1.0 2.0 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  16. 4 2012 2013 2014 2015 2016 2017 2018 2019 2020

    2021 2.10 2.12 2.13 3.0 Stackless Scala with Free Monads (Bjarnason) scalaz.Task
 scalaz.stream 2.11 Functional Programming in Scala (Bjarnason, Chiusano) Task 0.9 1.0 1.0 2.0 3.0 Scala Logo - CC Attribution 4.0 https://commons.wikimedia.org/wiki/File:Scala-full-color.svg Typelevel project logos by Zelenya http4s doobie cats Monix fs2 cats-effect
  17. CATS EFFECT 2 5 def fromCompletableFuture[A](fut: IO[CompletableFuture[A]]): IO[A] What’s Cats

    Effect 2 ? • Interop laye r • Library authors write against type classe s • Application developers choose the effect typ e • Reference implementation ? • Minimal ?
  18. CATS EFFECT 3 6 cats-effect-kernel cats-effect-core cats-effect-laws cats-effect-testkit cats-effect-std Type

    class hierarchy Concurrency primitives Console, Queue, PriorityQueue, Dequeue, Dispatcher, Hotswap, Semaphore, CountDownLatch, CyclicBarrier cats.effect.IO & related types
  19. CATS-EFFECT-CORE 7 import cats.effect.IO, scala.concurrent.duration. _ val prg = IO.sleep(1.second)

    *> IO.println("Hello, world!") prg.unsafeRunSync()
  20. CATS-EFFECT-CORE 7 import cats.effect.IO, scala.concurrent.duration. _ val prg = IO.sleep(1.second)

    *> IO.println("Hello, world!") prg.unsafeRunSync() Could not find an implicit IORuntime . Instead of calling unsafe methods directly, consider using cats.effect.IOApp, whic h runs your IO. If integrating with non-functional code or experimenting in a REPL / Worksheet , add the following import : import cats.effect.unsafe.implicits.globa l 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 yo u wish to use to execute IO programs. Please be sure to review thread pool best practices t o avoid unintentionally degrading your application performance . val res3 = prg.unsafeRunSync( ) ^ Compilation Faile d
  21. CATS-EFFECT-CORE 8 import cats.effect.IO, scala.concurrent.duration. _ val prg = IO.sleep(1.second)

    *> IO.println("Hello, world!") import cats.effect.unsafe.implicits.globa l prg.unsafeRunSync() // Hello, world!
  22. CATS-EFFECT-CORE 9 IO.sleep(1.second) ContextShift[IO] Timer[IO]

  23. CATS-EFFECT-CORE 9 IO.sleep(1.second) ContextShift[IO] Timer[IO] // CE2 (b: Blocker) =>

    b.delay[IO, Unit](Files.delete(path)) // CE3 - Blocker IO.blocking(Files.delete(path))
  24. CATS-EFFECT-CORE 1 0 • IO is much more full featured

    : • Sleeping / clock access without implicit instance s • Blocking & interruptible blockin g • Magical stack traces (aka tracing ) • Fairness / auto-yieldin g • Fiber local state
  25. CATS-EFFECT-CORE 1 1 import cats.effect.{IO, IOApp} object HelloWorld extends IOApp.Simple

    { def run: IO[Unit] = IO.println("Hello, world!") }
  26. CATS-EFFECT-CORE 1 1 import cats.effect.{IO, IOApp} object HelloWorld extends IOApp.Simple

    { def run: IO[Unit] = IO.println("Hello, world!") } import cats.effect.ExitCod e object UnixStyle extends IOApp { def run(args: List[String]): IO[ExitCode] = IO.println("Hello, world!").as(ExitCode.Success) }
  27. CATS-EFFECT-CORE 1 2 object IORuntime { def default: IORuntime =

    … def apply( compute: ExecutionContext, blocking: ExecutionContext, scheduler: Scheduler, shutdown: () => Unit, config: IORuntimeConfi g ): IORuntime = … } • Thread pools : • comput e • blockin g • schedule r • Configurable runtime parameters : • Auto-yield frequenc y • Cancellation check frequenc y • Tracin g • Much better defaults ! • JVM compute pool is a high performance work stealing pool from Vasil Vasile v • JS pools provide better fairness than s.c.ExecutionContext.global via polyfilled setImmediate (https://github.com/typelevel/cats- effect/pull/969)
  28. CATS-EFFECT-KERNEL 1 3 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative MonadCance l • Types which support cancelation, masking, & finalizatio n • Operations : • bracket, bracketCase, bracketFul l • def uncancelable[A](body: Poll[A] => F[A]): F[A] • Instances : • IO, SyncI O • Non-instances : • Coeval
  29. CATS-EFFECT-KERNEL 1 4 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative Spaw n • Types which support creation & racing of fiber s • Operations : • star t • cede, neve r • race, racePair, raceOutcom e • both, bothOutcom e • Instances : • I O • Non-instances : • SyncIO
  30. CATS-EFFECT-KERNEL 1 5 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative Concurren t • Types which creation of synchronization primitive s • Operations : • re f • deferre d • Instances : • I O • Non-instances : • SyncIO
  31. CATS-EFFECT-KERNEL 1 6 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative Cloc k • Types which allow access to current tim e • Operations : • monotoni c • realTim e Tempora l • Types which have both Concurrent and Clock instance s • Operations : • slee p • timeout
  32. CATS-EFFECT-KERNEL 1 7 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative Syn c • Synchronous FF I • Operations : • dela y • blockin g • interruptibl e Asyn c • Asynchronous FF I • Operations : • asyn c • evalO n The most powerful type classes are now at the bottom of the hierarchy, not the top!
  33. CATS-EFFECT-KERNEL 1 8 MonadError Spawn MonadCancel Concurrent Temporal Async Sync

    Defer Clock Applicative What’s gone? Why ? • Effect, ConcurrentEffec t • provided the ability to unsafely run an effec t • often used in interop layers with impure cod e • cats.effect.std.Dispatcher supports this for any Async[F] in most case s • LiftI O • converts IO[A] to F[A] • privileged IO over other effects
  34. USING KERNEL 1 9 import java.nio.file.{Files, Path} def delete(path: Path):

    IO[Unit] = IO.blocking(Files.delete(path))
  35. USING KERNEL 1 9 import java.nio.file.{Files, Path} def delete(path: Path):

    IO[Unit] = IO.blocking(Files.delete(path)) How can we generalize this for any effect type? ?
  36. USING KERNEL 1 9 import java.nio.file.{Files, Path} def delete(path: Path):

    IO[Unit] = IO.blocking(Files.delete(path)) How can we generalize this for any effect type? ? import java.nio.file.{Files, Path} def delete[F[_]: Sync](path: Path): F[Unit] = Sync[F].blocking(Files.delete(path))
  37. USING KERNEL 1 9 import java.nio.file.{Files, Path} def delete(path: Path):

    IO[Unit] = IO.blocking(Files.delete(path)) How can we generalize this for any effect type? ? import java.nio.file.{Files, Path} def delete[F[_]: Sync](path: Path): F[Unit] = Sync[F].blocking(Files.delete(path)) The callers must have a Sync[F] instance, which defeats the point of pushing Sync[F] to the bottom of the hierarchy! ☹
  38. USING KERNEL 2 0 import java.nio.file.{Files => JFiles, Path} trait

    Files[F[_]] { def delete(path: Path): F[Unit] } object Files { implicit def forSync[F[_]: Sync] = new Files[F] { def delete(path: Path): F[Unit] = Sync[F].blocking(JFiles.delete(path)) } } def doStuff[F[_]: Files]: F[Unit] = … Instead: - provide a capability trait, which limits the set of operations - provide an implicit instance for an effect type written in terms of Sync/Async - pass capabilities through usage sites via context bounds
  39. FUNCTIONAL STREAMS FOR SCALA 2 1 FS2 2.5. x •

    Cats Effect 2 • Scala 2.12, 2.13, and 3. 0 FS2 3. x • Cats Effect 3 • Scala 2.12, 2.13, and 3. 0 • Themes : • CE3 integration & resulting simplificatio n • Smoothing rough edges, not big change s • Capability trait s • Internal interpreter simplification
  40. FS2 2.X HELLO WORLD 2 2 import cats.effect.{Blocker, ExitCode, IO,

    IOApp, Resource} import fs2.{io, text, Stream} import java.nio.file.Path s object Converter extends IOApp { val converter: Stream[IO, Unit] = Stream.resource(Blocker[IO]).flatMap { blocker => def fahrenheitToCelsius(f: Double): Double = (f - 32.0) * (5.0/9.0) io.file.readAll[IO](Paths.get("testdata/fahrenheit.txt"), blocker, 4096) .through(text.utf8Decode) .through(text.lines) .filter(s => !s.trim.isEmpty && !s.startsWith("//")) .map(line => fahrenheitToCelsius(line.toDouble).toString) .intersperse("\n") .through(text.utf8Encode) .through(io.file.writeAll(Paths.get("testdata/celsius.txt"), blocker)) } def run(args: List[String]): IO[ExitCode] = converter.compile.drain.as(ExitCode.Success) }
  41. FS2 3.X HELLO WORLD 2 3 import cats.effect.{IO, IOApp} import

    fs2.{io, text, Stream} import java.nio.file.Path s object Converter extends IOApp.Simple { val converter: Stream[IO, Unit] = { def fahrenheitToCelsius(f: Double): Double = (f - 32.0) * (5.0/9.0) io.file.Files[IO].readAll(Paths.get(“testdata/fahrenheit.txt”), 4096) .through(text.utf8Decode) .through(text.lines) .filter(s => !s.trim.isEmpty && !s.startsWith("//")) .map(line => fahrenheitToCelsius(line.toDouble).toString) .intersperse("\n") .through(text.utf8Encode) .through(io.file.Files[IO].writeAll(Paths.get("testdata/celsius.txt"))) } def run: IO[Unit] = converter.compile.drai n }
  42. WRAP-UP 2 4 Summar y • CE3 is the next

    generation of industrial strength, functional concurrency with a major focus on usabilit y What’s next ? • Continue port of Typelevel ecosyste m • Http4s, Doobie, Skun k • Davenportvers e • Moni x • Get involved ! • Help port librarie s • Build application s • Blog posts, example s Acknowledgement s • Raas Ahsa n • Jakub Kozłowsk i • Fabio Labell a • Ben Plomme r • Tim Spenc e • Daniel Spiewa k • Vasil Vasile v • Diego E. Alonso Bla s • …and many contributors of code, ideas, discussions, documentation, and advocac y