1

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

Zeke1999
  • 35
  • 1
  • 5

2 Answers2

2

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.

Dylan
  • 13,645
  • 3
  • 40
  • 67
0

An experiment with more Tasks:

    val taskOne = Task {
      Thread.sleep(4000)
      println("First executed")
      1
    }
    val taskTwo = Task {
      Thread.sleep(2000)
      println("Second executed")
      2
    }
    val taskThree = Task {
      Thread.sleep(1000)
      println("Third executed")
      3
    }
    val taskFour = Task {
      Thread.sleep(5000)
      println("Fourth executed")
      4
    }

    Task.parSequenceUnordered(List(taskOne, taskTwo, taskThree, taskFour)).runAsync( result => result match {
      case Right(value) => println(value)
      case Left(value) => value
    }

Resulted in:

Second executed
Third executed
First executed
Fourth executed
List(4, 1, 3, 2)

This shows that the results are returned in opposite order when using Task.parSequenceUnordered( ), from last completed to first completed.

Zeke1999
  • 35
  • 1
  • 5