0

I have the following two pieces of code written in Scala/Monix:

def f1(input) =
  for {
    a <- task1(input)
    b <- task2(a)
    c <- task3(b)
  } yield (c).runSyncUnsafe

and

def f2(input) = {
  val a = task1(input).runSyncUnsafe
  val b = task2(a).runSyncUnsafe
  task3(b).runSyncUnsafe
}

I think the version f1 is better as it fully async and it doesn't block threads and my assumption is that, if there are many tasks running, the first should perform better in multithreading.

I know I should write a test to compare the two implementations but it would require a lot of refactoring of the legacy code. Also the profiling of the two versions is not easy in our specific situation so I'm asking here first, hoping for an answer from somebody with a lot of Scala/Monix experience:

How should the two compare in terms of performance under heavy load? Is this a real concern or is it a non-issue?

vidi
  • 2,056
  • 16
  • 34

1 Answers1

1

As a general rule is better to stay async for as long as possible. So you could write f1 like this:

def f1(input) =
  for {
    a <- task1(input)
    b <- task2(a)
    c <- task3(b)
  } yield c

The caller can then decide whether to call runSyncUnsafe or an async call (runAsync, runOnComplete) or flatMap it with another task. This removes the Unsafe call from your code and leaves it to the caller to decide whether to be safe or not.

As far as performance goes, the tasks will be evaluated sequentially either way because later tasks depend on the results of earlier tasks.

Tim
  • 26,753
  • 2
  • 16
  • 29
  • my concern here is if the threads is blocked while running runSyncUnsafe then the runtime cannot use it in other computations while if you stay async the waits are not blocking so the the runtime can use all the threads – vidi Oct 04 '18 at 14:25