Scala low-key actor, recursive call faster than using vars?

Sample code below. I'm a little curious why MyActor is faster than MyActor2. MyActor recursively calls the process / reacts and saves the state in the parameters of the function, while MyActor2 saves the state in vars. MyActor even has the additional overhead of setting state, but it still works faster. I am wondering if there is a good explanation for this, or maybe I am doing something “wrong”.

I understand that the difference in performance is not significant, but the fact that it exists and is consistent makes me curious about what is happening here.

Ignoring the first two runs as a warm-up, I get:

MyActor: 559 511 544 529

against.

MyActor2: 647 613 654 610

import scala.actors._

object Const {
  val NUM = 100000
  val NM1 = NUM - 1
}

trait Send[MessageType] {
  def send(msg: MessageType)
}

// Test 1 using recursive calls to maintain state

abstract class StatefulTypedActor[MessageType, StateType](val initialState: StateType) extends Actor with Send[MessageType] {
  def process(state: StateType, message: MessageType): StateType

  def act = proc(initialState)

  def send(message: MessageType) = {
    this ! message
  }

  private def proc(state: StateType) {
    react {
      case msg: MessageType => proc(process(state, msg))
    }
  }
}

object MyActor extends StatefulTypedActor[Int, (Int, Long)]((0, 0)) {
  override def process(state: (Int, Long), input: Int) = input match {
    case 0 =>
      (1, System.currentTimeMillis())
    case input: Int =>
      state match {
        case (Const.NM1, start) =>
          println((System.currentTimeMillis() - start))
          (Const.NUM, start)
        case (s, start) =>
          (s + 1, start)
      }
  }
}

// Test 2 using vars to maintain state

object MyActor2 extends Actor with Send[Int] {
  private var state = 0
  private var strt = 0: Long

  def send(message: Int) = {
    this ! message
  }

  def act =
    loop {
      react {
        case 0 =>
          state = 1
          strt = System.currentTimeMillis()
        case input: Int =>
          state match {
            case Const.NM1 =>
              println((System.currentTimeMillis() - strt))
              state += 1
            case s =>
              state += 1
          }
      }
    }
}


// main: Run testing

object TestActors {
  def main(args: Array[String]): Unit = {
    val a = MyActor
    //    val a = MyActor2
    a.start()
    testIt(a)
  }

  def testIt(a: Send[Int]) {
    for (_ <- 0 to 5) {
      for (i <- 0 to Const.NUM) {
        a send i
      }
    }
  }
}

: . MyActor2, vars, 10% . ... : , , ... () .

MyActor2:

  override def act() =
    react {
      case 0 =>
        state = 1
        strt = System.currentTimeMillis()
        act()
      case input: Int =>
        state match {
          case Const.NM1 =>
            println((System.currentTimeMillis() - strt))
            state += 1
          case s =>
            state += 1
        }
        act()
    }
+5
3

( , , ).

, react:

  • ;
  • , ;
  • , (Actor.suspendException);

, , react, , , , .

loop react, ( № 1, process ), react , . , .


( ):

, , , , , , .

+3

. - , . . , , .

0

( scala -Dactors.corePoolSize=1!). , ; , loop, - . Loop , "andThen", . , , , scala.actors.Scheduler$.impl ExceptionBlob.

0

All Articles