Because Task.parSequenceUnordered "is like parSequence, except that you don’t get ordering for results or effects.", I would expect the following to return List(2, 1):
import monix.eval.Task
import monix.execution.Scheduler.Implicits.global
object TaskSequence extends App {
val taskOne = Task {
Thread.sleep(3000)
println("First executed")
1
}
val taskTwo = Task {
Thread.sleep(2000)
println("Second executed")
2
}
val parallelUnordered = Task.parSequenceUnordered(List(taskOne, taskTwo)).runSyncUnsafe()
println(s"Return vals for Task.parSequenceUnordered( ) were $parallelUnordered")
}
However, I get List(1, 2) as a result. Using .runAsync( ) doesn't make a difference either:
Task.parSequenceUnordered(List(taskOne, taskTwo)).runAsync( result => result match {
case Right(value) => println(value)
case Left(value) => value
})
Thread.sleep(5000) // don't let program exit
The second Task finishes first, so I should get the 2 back first in the return List, right? Can any Monix experts weigh in? Thanks
It's because of the implementation of parSequenceUnordered
, which builds the result list by using O(1) prepend operations.
There's a
private sealed abstract class State[+A] {
def isActive: Boolean
def enqueue[B >: A](value: B): State[B]
}
to represent the internal state machine for the task, and a couple of the State subclasses look like
final case class Active[+A](list: List[A], remaining: Int) extends State[A] {
def isActive = true
def enqueue[B >: A](value: B): Active[B] =
Active(value :: list, remaining - 1)
}
So because it uses value :: list
to accumulate the results, they are built in reverse in terms of which result comes in first.