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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With