1

I'm experimenting with futures. So i created a huge list of random numbers and then separated it in 3 groups to run them parallelly with some code

val itemsInGroup = 500000
val numbers: List[Int] = 1.to(1500000).map(v => Random.nextInt(20)).toList
val groups: List[List[Int]] = numbers.grouped(itemsInGroup).toList.take(3)

val future = Future.sequence(groups.map(gr => Future[Int] {countSum(gr)}))
future andThen {
  case Success(threeNumbers) => println(threeNumbers)
}

what makes countSum is not too much important, just to take time i use this code

case class Person(name: String, age: Int) {
  def age10: Int = age - age % 10
}

def countSum(lst: List[Int]): Int = lst.map(v => Person("John", v).age10).sum

as a result of a future i print list of 3 numbers. The problem is it doesnt work every time. Sometimes andThen works sometimes not, and if i change itemsInGroup value to small amounts, it works more frequently than big amounts of elements. So i suspect that there's a kind of implicit timeout or something otherwise i can't explain such phenomen.

Please, your tips appreciated

UPD Actually so much code were not needed, even simple example

val ft = Future {
  Thread.sleep(10)
  10
}

ft andThen {
  case Success(value) => println("Here i work")
}

works the same way - sometimes works sometimes not, the more delay the less possibility that it will complete

Dmitry Reutov
  • 2,995
  • 1
  • 5
  • 20
  • 60% of the time, it works all the time. :D – stefanobaghino Jan 08 '20 at 14:28
  • 1
    Jokes aside, I'm trying it on Scastie but it seems to work without any problem. https://scastie.scala-lang.org/hlUiDdMlTjyzyNmXj8sgOw – stefanobaghino Jan 08 '20 at 14:28
  • 1
    I would suggest to explicitly handle the `Failure` case to gather some feedback, I suspect you should see something out of it. – stefanobaghino Jan 08 '20 at 14:29
  • @stefanobaghino, please example of "explicitly handle the Failure" – Dmitry Reutov Jan 08 '20 at 14:40
  • 1
    in the `andThen` you pass a partial function that only handles the `Success` case. If you add a case for `Failure` you can extract the exception that caused it and inspect it. – stefanobaghino Jan 08 '20 at 14:44
  • 1
    The Scala documentation includes an example of how to handle both cases: https://www.scala-lang.org/api/2.13.1/scala/concurrent/Future.html#andThen[U](pf:PartialFunction[scala.util.Try[T],U])(implicitexecutor:scala.concurrent.ExecutionContext):scala.concurrent.Future[T] – stefanobaghino Jan 08 '20 at 14:45
  • @stefanobaghino, this i know. No, it doesnt work, andThen simply skipped – Dmitry Reutov Jan 08 '20 at 14:52

1 Answers1

2

Your main app thread is probably being terminated before your future completes. Try the following code.

import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Success, Failure}

val future = Future {
  Thread.sleep(10)
  10
}

val result = future andThen {
  case Success(value) => println("Here i work")
  case Failure(ex) => println(s"Error: ${ex.getMessage}")
}

println(Await.result(result, Duration.Inf)) // Only if you are sure it will ever finish, still it is recommended to use an appropriate timeout.
Andre Fagundes
  • 131
  • 2
  • 8