how does building a big task computation compare to execute synchronously several steps?

72 views Asked by At

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?

1

There are 1 answers

1
Tim On

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.