Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to elegantly perform multiple effects in parallel with ZIO

Tags:

scala

scalaz

zio

I know that I can use

import zio.Task

def zip3Par[A, B, C](a: Task[A], b: Task[B], c: Task[C]): Task[(A, B, C)] =
  a.zipPar(b).zipWithPar(c) { case ((a, b), c) => (a, b, c) }

def zip4Par[A, B, C, D](a: Task[A], b: Task[B], c: Task[C], d: Task[D]): Task[(A, B, C, D)] =
  zip3Par(a, b, c).zipWithPar(d) { case ((a, b, c), d) => (a, b, c, d) }

to execute 3 or 4 tasks in parallel, but I wounder if there is a more elegant solution?

like image 385
Matthias Langer Avatar asked Jul 13 '19 07:07

Matthias Langer


2 Answers

You could just use ZIO.collectAllPar with list of tasks:

def collectTasks(tasks: Task[Int]*):Task[List[Int]] = ZIO.collectAllPar(tasks)

Then you could use it like:

val t1 = Task.effect{
  Thread.sleep(100)
  println("t1 started")
  Thread.sleep(1000)
  1
}

val t2 = Task.effect{
  println("t2 started")
  Thread.sleep(1000)
  2
}


val t3 = Task.effect{
  println("t3 started")
  Thread.sleep(1000)
  3
}

(new DefaultRuntime() {}).unsafeRun(collectTasks(t1,t2,t3))

and it will run all your tasks concurrently.

A generic solution using tuples instead of a list would be hard to achieve in Scala 2 without shapeless. It would change in Scala 3, because then they could be handled as heterogenous lists.

like image 105
Krzysztof Atłasik Avatar answered Sep 22 '22 13:09

Krzysztof Atłasik


Also note that there is the <&> combinator. This is an alias for zipPar. This will yield a tuple, and if you use for comprehensions I would suggest to have a look at better-monadic-for which fixes the issues with tuples in for comprehensions

Here's an example of using the <&> combinator with map:

(t1 <&> t2 <&> t3 <&> t4) map { case i1 <*> i2 <*> i3 <*> i4 => s"$i1, $i2, $i3, $i4" }

ZIO.collectAllPar and ZIO.collectAllParN only work when all the ZIO have the same return type. That was not the question.

like image 42
Mark Avatar answered Sep 20 '22 13:09

Mark