0
votes

For a practice job interview, my friend asked me to implement merge sort with Scala actors within an allotted period of time.

The code ended up looking like this:

https://dl.dropboxusercontent.com/u/214507961/MergeActor.scala

Basically, the application would start like so:

import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import akka.actor.ActorSystem
import akka.actor.{ActorRef, Props}

def main(args: Array[String]): Unit = {

    val system = ActorSystem("CrappyActor1")

    implicit val timeout = Timeout(2.second)
    implicit val ec = system.dispatcher

    val firstActor: ActorRef = system.actorOf(Props[SortActor])
    val result = firstActor ? UnsortedList(List(1,3,2,4,-1))
    result.onSuccess {
      case SortedList(element) => Print.line("" + element.toString)
      case _ => Print.asrt(false, "Only a Sorted list was supposed to arrive.")
    }
    result.onFailure {
      case _ => Print.asrt(false, "Failure.")
    }
    system.shutdown()
}

^ The first actor would be created and passed an unsorted list of numbers. It would receive this list and if the length of the list was greater than two, it would split in half the list, giving each half to a new child actor.

If the list had only 1 or 2 elements, the list would be sorted and sent back to the sender/parent actor until a fully sorted list was returned.

The thing is, in "MergeActor.scala" on line 62, I needed to add:

Thread.sleep(5000) // This keeps the sender in existence.

^ or else the merge sort didn't finish. Why is this sleep necessary? How would you do it?

* Update *

Adding "Thread.sleep(10000)" at the end of "main" before "system.shutdown()" didn't work. Commenting out "Thread.sleep(5000)" in "MergeActor.scala" caused "main" to end in "result.onFailure".

"Failure: akka.pattern.AskTimeoutException: Ask timed out on [Actor[akka://CrappyActor1/user/$a#-1508387879]] after [2000 ms]" in thread CrappyActor1-akka.actor.default-dispatcher-3:

Without "Thread.sleep(5000)", the result does not come back before the two second timeout.

Also, I get this error just before failure:

[INFO] [03/04/2016 15:34:05.696] [CrappyActor1-akka.actor.default-dispatcher-3] [akka://CrappyActor1/deadLetters] Message [mergeactors.MergeActor$SortedList] from Actor[akka://CrappyActor1/user/$a/$b#1429046332] to Actor[akka://CrappyActor1/deadLetters] was not delivered. [1] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
1
I assume merging is executed in slave threads. You have to keep you main thread alive otherwise it's normally finish work and other threads shutdown later aswel.vvg
@rumoku I don't know anything about Akka. All I know is that if I comment out "Thread.sleep(5000)", I get "akka.pattern.AskTimeoutException" in the main thread, the thread that creates the parent actor. Also, I don't think that I'm doing any merging - the threads that do the merge sort just "PoisonPill" themselves after they return the sorted list. Keeping the main thread alive doesn't help.Michael Lafayette

1 Answers

1
votes

A possible cause could be that the program exits before the results return.

You have to keep in mind that all execution is decoupled and when the Mainexits the program ends even if there is some work done in antoher thread or actor.

For starters I would recommend using only one concurrency modeland not mix Actors with Futures. This happens when one uses the ask or ? -pattern.

In this way you now also have to keep possible timeouts in mind.

Update: answer to extended question

The problem you describe is not connected to actors but to Scala Futures. Here you get the basic documentation and usage examples: http://docs.scala-lang.org/overviews/core/futures.html.

Try

  Await.result(result, Duration.Inf)