Актеры Akka, Futures, и замыкания

Я читал в документации Akka, что опасно закрывать переменные от объемлющего актора.

Предупреждение

В этом случае необходимо тщательно избегать закрытия содержащий ссылку на актера, т.е.не вызывать методы на включающего актера из класса анонимного актера. Это бы нарушить инкапсуляцию актера и может привести к ошибкам синхронизации и условия гонки, потому что код другого актора будет запланирован одновременно с окружающим актером.

Теперь у меня есть два актора, один из которых что-то запрашивает у второго и что-то делает с результатом. В приведенном ниже примере актор Accumulatorизвлекает числа из актора NumberGeneratorи складывает их, сообщая сумму по пути.

Это можно сделать как минимум двумя разными способами, как показано в этом примере с двумя разными функциями receive( Avs B). Разница между ними в том, что Aне закрывается по переменной counter; вместо этого он ожидает целое число и суммирует его, в то время как Bсоздает Future, который закрывает counterи выполняет суммирование. Это происходит внутри анонимного актера, созданного только для обработки onSuccess, если я правильно понимаю, как это работает.

import com.esotericsoftware.minlog.Log

import akka.actor.{Actor, Props}
import akka.pattern.{ask, pipe}
import akka.util.Timeout
import akka.util.duration._

case object Start
case object Request


object ActorTest {
  var wake = 0

  val accRef = Main.actorSystem.actorOf(Props[Accumulator], name = "accumulator")
  val genRef = Main.actorSystem.actorOf(Props[NumberGenerator], name = "generator")

  Log.info("ActorTest", "Starting !")

  accRef ! Start
}

class Accumulator extends Actor {
  var counter = 0

  implicit val timeout = Timeout(5 seconds)

  // A: WITHOUT CLOSURE
  def receive = {
    case Start => ask(ActorTest.genRef, Request).mapTo[Int] pipeTo self
    case x: Int => counter += x; Log.info("Accumulator", "counter = " + counter); self ! Start
  }
  // B: WITH CLOSURE
  def receive = {
    case Start => ask(ActorTest.genRef, Request).mapTo[Int] onSuccess {
      case x: Int => counter += x; Log.info("Accumulator", "counter = " + counter); self ! Start
    }
  }
}

class NumberGenerator extends Actor {
  val rand = new java.util.Random()

  def receive = {
    case Request => sender ! rand.nextInt(11)-5
  }
}

Является ли использование замыканий в этом случае абсолютно злом? Конечно, я мог бы использовать AtomicInteger вместо Int или в каком-то сетевом сценарии, используя, скажем, nettyвыполнить операцию записи на канале threadsafe, но это не моя точка зрения. здесь.

Рискуя задать нелепый вопрос: есть ли способ для Future onSuccess выполнить в этомакторе вместо анонимного промежуточного актора, безопределения случая в функция получения?

РЕДАКТИРОВАТЬ

Чтобы выразиться более четко, мой вопрос: есть ли способ заставить серию Futures работать в том же потоке, что и данный Актер?

12
задан gsimard 21 June 2012 в 15:11
поделиться