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