Пример кода ниже. Мне немного любопытно, почему MyActor быстрее, чем MyActor2. MyActor рекурсивно вызывает процесс / реагирует и сохраняет состояние в параметрах функции, тогда как MyActor2 сохраняет состояние в переменных. MyActor даже имеет дополнительные накладные расходы на изменение состояния, но все равно работает быстрее. Мне интересно, есть ли хорошее объяснение этому или, может быть, я делаю что-то "не так".
Я понимаю, что разница в производительности не значительна, но тот факт, что она есть и соответствует, заставляет меня любопытно, что здесь происходит.
Игнорируя первые два прогона как разминку, я получаю:
MyActor:
559
511
544
529
против
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, основанный на переменных, перепрыгнул и теперь может быть примерно на 10% быстрее. Итак ... урок: если вы уверены, что у вас не останется переполнение стека невыполненными сообщениями, и вы хотите выжать каждую небольшую производительность ... не используйте loop и просто вызывайте act () метод рекурсивный.
Изменение для 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()
}