Note that there are some explanatory texts on larger screens.

plurals
  1. POWhat are some opportunities improve performance / concurrency in the following Scala + Akka code?
    primarykey
    data
    text
    <p>I am looking for opportunities to increase concurrency and performance in my Scala 2.9 / Akka 2.0 RC2 code. Given the following code:</p> <pre><code>import akka.actor._ case class DataDelivery(data:Double) class ComputeActor extends Actor { var buffer = scala.collection.mutable.ArrayBuffer[Double]() val functionsToCompute = List("f1","f2","f3","f4","f5") var functionMap = scala.collection.mutable.LinkedHashMap[String,(Map[String,Any]) =&gt; Double]() functionMap += {"f1" -&gt; f1} functionMap += {"f2" -&gt; f2} functionMap += {"f3" -&gt; f3} functionMap += {"f4" -&gt; f4} functionMap += {"f5" -&gt; f5} def updateData(data:Double):scala.collection.mutable.ArrayBuffer[Double] = { buffer += data buffer } def f1(map:Map[String,Any]):Double = { // println("hello from f1") 0.0 } def f2(map:Map[String,Any]):Double = { // println("hello from f2") 0.0 } def f3(map:Map[String,Any]):Double = { // println("hello from f3") 0.0 } def f4(map:Map[String,Any]):Double = { // println("hello from f4") 0.0 } def f5(map:Map[String,Any]):Double = { // println("hello from f5") 0.0 } def computeValues(immutableBuffer:IndexedSeq[Double]):Map[String,Double] = { var map = Map[String,Double]() try { functionsToCompute.foreach(function =&gt; { val value = functionMap(function) function match { case "f1" =&gt; var v = value(Map("lookback"-&gt;10,"buffer"-&gt;immutableBuffer,"parm1"-&gt;0.0)) map += {function -&gt; v} case "f2" =&gt; var v = value(Map("lookback"-&gt;20,"buffer"-&gt;immutableBuffer)) map += {function -&gt; v} case "f3" =&gt; var v = value(Map("lookback"-&gt;30,"buffer"-&gt;immutableBuffer,"parm1"-&gt;1.0,"parm2"-&gt;false)) map += {function -&gt; v} case "f4" =&gt; var v = value(Map("lookback"-&gt;40,"buffer"-&gt;immutableBuffer)) map += {function -&gt; v} case "f5" =&gt; var v = value(Map("buffer"-&gt;immutableBuffer)) map += {function -&gt; v} case _ =&gt; println(this.unhandled()) } }) } catch { case ex: Exception =&gt; ex.printStackTrace() } map } def receive = { case DataDelivery(data) =&gt; val startTime = System.nanoTime()/1000 val answers = computeValues(updateData(data)) val endTime = System.nanoTime()/1000 val elapsedTime = endTime - startTime println("elapsed time is " + elapsedTime) // reply or forward case msg =&gt; println("msg is " + msg) } } object Test { def main(args:Array[String]) { val system = ActorSystem("actorSystem") val computeActor = system.actorOf(Props(new ComputeActor),"computeActor") var i = 0 while (i &lt; 1000) { computeActor ! DataDelivery(i.toDouble) i += 1 } } } </code></pre> <p>When I run this the output (converted to microseconds) is</p> <pre><code>elapsed time is 4898 elapsed time is 184 elapsed time is 144 . . . elapsed time is 109 elapsed time is 103 </code></pre> <p>You can see the JVM's incremental compiler kicking in.</p> <p>I thought that one quick win might be to change</p> <pre><code> functionsToCompute.foreach(function =&gt; { </code></pre> <p>to</p> <pre><code> functionsToCompute.par.foreach(function =&gt; { </code></pre> <p>but this results in the following elapsed times</p> <pre><code>elapsed time is 31689 elapsed time is 4874 elapsed time is 622 . . . elapsed time is 698 elapsed time is 2171 </code></pre> <p><strong>Some info:</strong></p> <p>1) I'm running this on a Macbook Pro with 2 cores.</p> <p>2) In the full version, the functions are long running operations that loop over portions of the mutable shared buffer. This doesn't appear to be a problem since retrieving messages from the actor's mailbox is controlling the flow, but I suspect it could be an issue with increased concurrency. This is why I've converted to an IndexedSeq.</p> <p>3) In the full version, the functionsToCompute list may vary, so that not all items in the functionMap are necessarily called (i.e.) functionMap.size may be much larger than functionsToCompute.size</p> <p>4) The functions can be computed in parallel, but the resultant map must be complete before returning</p> <p><strong>Some questions:</strong></p> <p>1) What can I do to make the parallel version run faster?</p> <p>2) Where would it make sense to add non-blocking and blocking futures?</p> <p>3) Where would it make sense to forward computation to another actor?</p> <p>4) What are some opportunities for increasing immutability/safety?</p> <p>Thanks, Bruce</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload