mon ix i n practice - ilya-murzinov.github.io · monix-reactive - observable, observer (push-based...

48
Monix in practice Ilya Murzinov https://twitter.com/ilyamurzinov https://github.com/ilya-murzinov Slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 1 / 30

Upload: others

Post on 27-Jul-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Monix in practiceIlya Murzinov

https://twitter.com/ilyamurzinov

https://github.com/ilya-murzinov

Slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf

1 / 30

Page 2: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 2 / 30

Page 3: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Referential transparencydef goodFunction() = 2 + 2

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 3 / 30

Page 4: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Referential transparencydef goodFunction() = 2 + 2

def badFunction() = { sendMessage() 2 + 2}

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 3 / 30

Page 5: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Monix

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 4 / 30

Page 6: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Monix modulesmonix-eval - Task, Coeval, MVar etc.

monix-reactive - Observable, Observer (push-based streaming)

monix-tail - Iterant (pull-based streaming)

monix-execution - Scheduler & bunch of performance hacks

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 5 / 30

Page 7: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task[A]

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 6 / 30

Page 8: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Future

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 9: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 10: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 11: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 12: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Not stack-safe

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 13: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Not stack-safe

monix.Task:

Lazy (ref. transparent)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 14: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Not stack-safe

monix.Task:

Lazy (ref. transparent)

Cancellable

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 15: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Not stack-safe

monix.Task:

Lazy (ref. transparent)

Cancellable

Not always asyncronous

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 16: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task vs Futurescala.concurrect.Future:

Eager (thus not ref. transparent)

Not cancellable

Always asyncronous

Not stack-safe

monix.Task:

Lazy (ref. transparent)

Cancellable

Not always asyncronous

Stack (and heap) safe

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 7 / 30

Page 17: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

SchedulerSchedule delayed execution

Schedule periodic execution

Provide cancellation token

Use different execution models

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 8 / 30

Page 18: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

ExecutionModelAlwaysAsyncExecution

SynchronousExecution

BatchedExecution

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 9 / 30

Page 19: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

SchedulerScheduler.computation(name = "my-computation")

Scheduler.io(name = "my-io")

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 10 / 30

Page 20: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

SchedulerScheduler.computation(name = "my-computation")

Scheduler.io(name = "my-io")

Scheduler.fixedPool("my-fixed-pool", 10)

Scheduler.singleThread("my-single-thread")

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 10 / 30

Page 21: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Creating a taskimport monix.eval.Task

// eagerly evaluates the argumentTask.now(42)Task.now(println(42))

// suspends argument evaluationTask.eval(println(42))

// suspends evaluation + makes it asynchronousTask(println(42))

...

Task.evalOnce(...)Task.defer(...)Task.deferFuture(...)Task.deferFutureAction(...)

...

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 11 / 30

Page 22: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Thread shiftingval t = Task.eval(println(42))

t.executeAsync

t.executeOn(io)

t.asyncBoundary(io)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 12 / 30

Page 23: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Thread shiftingimport monix.execution.Schedulerimport monix.execution.Scheduler.Implicits.global

lazy val io = Scheduler.io(name = "my-io")

val source = Task.eval(println( s"Running on thread: ${Thread.currentThread.getName}"))

val async = source.executeAsyncval forked = source.executeOn(io)

val onFinish = Task.eval(println( s"Ends on thread: ${Thread.currentThread.getName}"))

source // executes on main .flatMap(_ => source) // executes on main .flatMap(_ => async) // executes on global .flatMap(_ => forked) // executes on io .asyncBoundary // switch back to global .doOnFinish(_ => onFinish) // executes on global .runAsync

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 13 / 30

Page 24: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Composing tasksval extract: Task[Seq[String]] = ???val transform: Seq[String] => Task[Seq[WTF]] = ???val load: Seq[WTF] => Task[Unit] = ???

for { strings <- extract transformed <- transform(strings) _ <- load(transformed)} yield ()

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 14 / 30

Page 25: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Composing tasksval extract: Task[Seq[String]] = ???val transform: Seq[String] => Task[Seq[WTF]] = ???val load: Seq[WTF] => Task[Unit] = ???

for { strings <- extract transformed <- transform(strings) _ <- load(transformed)} yield ()

val extract1: Task[Seq[String]] = ???val extract2: Task[Seq[String]] = ???val extract3: Task[Seq[String]] = ???

val extract = Task.parMap3(extract1, extract2, extract3)(_ :+ _ :+ _)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 14 / 30

Page 26: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Composing tasksval tasks: Seq[Task[A]] = Seq(task1, task2, ...)

// Seq[Task[A]] => Task[Seq[A]]Task.sequence(tasks)

Task.gather(tasks)

Task.gatherUnordered(tasks)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 15 / 30

Page 27: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Composing tasksval tasks: Seq[Task[A]] = Seq(task1, task2, ...)

// Seq[Task[A]] => Task[Seq[A]]Task.sequence(tasks)

Task.gather(tasks)

Task.gatherUnordered(tasks)

// Seq[Task[A]] => Task[A]Task.raceMany(tasks)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 15 / 30

Page 28: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task cancellationval task = ???

val f: CancelableFuture[Unit] = t.runAsync

f.cancel()

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 16 / 30

Page 29: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task cancellationval task = ???

val f: CancelableFuture[Unit] = t.runAsync

f.cancel()

Task { Thread.sleep(100); println(42) } .doOnCancel(Task.eval(println("On cancel"))) .runAsync .cancel()

Thread.sleep(1000)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 16 / 30

Page 30: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task cancellationimport monix.execution.Scheduler.Implicits.global

val sleep = Task(Thread.sleep(100))

val t = sleep.flatMap(_ => Task.eval(println(42)))

t.runAsync.cancel()

Thread.sleep(1000)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 17 / 30

Page 31: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Task cancellationimport monix.execution.Scheduler.Implicits.global

val sleep = Task(Thread.sleep(100)).cancelable

val t = sleep.flatMap(_ => Task.eval(println(42)))

t.runAsync.cancel()

Thread.sleep(1000)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 18 / 30

Page 32: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 19 / 30

Page 33: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 34: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Cancellable

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 35: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Cancellable

Safe (doesn't expose unsafe or blocking operations)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 36: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Cancellable

Safe (doesn't expose unsafe or blocking operations)

Allows fine-grained control over execution

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 37: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Cancellable

Safe (doesn't expose unsafe or blocking operations)

Allows fine-grained control over execution

Models single producer - multiple consumers communication

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 38: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Observable[A]Lazy (ref. transparent)

Cancellable

Safe (doesn't expose unsafe or blocking operations)

Allows fine-grained control over execution

Models single producer - multiple consumers communication

Non-blocking back-pressure

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 20 / 30

Page 39: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Monix vs Akka streamsMonix has

Simpler API

Lighter (no dependency on actor framework)

Better execution control

Easier to understand internals

Faster

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 21 / 30

Page 40: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Performanceprivate[this] val list = 1 to 100

@Benchmarkdef monixMerge: Int = { val observables = list .map(_ => Observable.fromIterable(list).executeAsync)

Observable .merge(observables: _*)(OverflowStrategy.BackPressure(10)) .foldL .runSyncUnsafe(1.seconds)}

@Benchmarkdef akkaMerge: Int = { val source: Source[Int, NotUsed] = Source(list) val f = list .map(_ => source) .fold(Source.empty)(_.merge(_)) .runWith(Sink.fold(0)(_ + _))

Await.result(f, 1.second)}

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 22 / 30

Page 41: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Performance# Run complete. Total time: 00:06:45Do not assume the numbers tell you what you want them to tell.Benchmark Mode Cnt Score Error UnitsMonixBenchmark.akkaMerge thrpt 10 46.207 ± 0.849 ops/sMonixBenchmark.monixMerge thrpt 10 531.182 ± 37.332 ops/s

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 23 / 30

Page 42: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Example

Server Event source

Client 1

Client 2

Client 3

Client N

...

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 24 / 30

Page 43: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Exampleval acceptClient: Task[(Long, Data)] = ???

def handleClientJoin(id: Long, data: Data, state: State): Task[State] = ???

def clientSubscriber(mState: MVar[State]) = Observable.repeat(()) .doOnSubscribe(() => println(s"Client subscriber started")) .mapTask(_ => acceptClient) .mapTask { case (id, s) => for { state <- mState.take newState <- handleClientJoin(id, s, state) _ <- mState.put(newState) } yield () } .completedL

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 25 / 30

Page 44: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Exampleval acceptEventSource: Task[Iterator[Event]] = ???

def handleEvent(event: Event, state: State): Task[State]

def eventSourceProcessor(mState: MVar[State]) = Observable.repeat(()) .doOnSubscribe(() => println(s"Event processor started")) .mapTask(_ => acceptEventSource) .flatMap(it => Observable.fromIterator(it) .mapTask(e => for { state <- mState.take newState <- handleEvent(e, state) _ <- mState.put(newState) } yield ())) .headL

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 26 / 30

Page 45: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Exampleval io = Scheduler.io()val computation = Scheduler.computation()

for { initialState <- MVar(State()) c = clientSubscriber(initialState).executeOn(io) e = eventSourceProcessor(initialState).executeOn(computation) _ <- Task.gatherUnordered(Seq(c, e))} yield ()

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 27 / 30

Page 46: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

ReferencesMonix (https://monix.io)

Monix vs Cats-Effect

Scalaz 8 IO vs Akka (typed) actors vs Monix @ SoftwareMill

Solution of the example (https://github.com/ilya-murzinov/seuraajaa)

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 28 / 30

Page 47: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Questions?

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 29 / 30

Page 48: Mon ix i n practice - ilya-murzinov.github.io · monix-reactive - Observable, Observer (push-based streaming) monix-tail - Iterant (pull-based streaming) monix-execution - Scheduler

Thanks!

Monix in practice - Ilya Murzinov, slides: https://ilya-murzinov.github.io/slides/scalaspb2018.pdf 30 / 30