Последовательность доставки сообщений в акковых актерах

Я новичок в Akka и не нашел ответ в справочном руководстве.

Предположим, что у нас есть удаленные участники, распределенные в кластере из 3 машин (A, B, C), где один актер живет на каждой машине, а другие имеют actorRef для 2 других, то есть:

Machine A:
A (real actor)
-> B (ref)
-> C (ref)

Machine B:
-> A (ref)
B (real actor)
-> C (ref)

Machine C:
-> A (ref)
-> B (ref)
C (real actor)

Актер А выполняет следующий код:

bRef ! msg1
bRef ! msg2

Актер B выполняет следующий код в обработчике сообщений:

case msg1 => 
    cRef ! msg3
    aRef ! msg4

Актер C выполняет следующий код в обработчике сообщений:

case msg3 => 
    aRef ! msg5

Могу ли я сделать следующие предположения (если есть):

  • Актер B получает сообщение msg1 перед тем, как он получит msg2

  • Актер А получает сообщение msg5, пока не получит сообщение msg4

И следующий вопрос, который, вероятно, приводит к пониманию вышеизложенного: Сообщение отправлено! оператора через сеть по-настоящему асинхронно или он ждет, пока получающий почтовый ящик не получит его? То есть строка

bRef ! msg1

пока актер B не получит сообщение в своем почтовом ящике или не создаст поток, который обрабатывает доставку, и продолжит выполнение

bRef ! msg2

прежде чем он даже узнает, что актер B получил msg1?

Ответ 1

Для (1) у вас есть гарантия, что msg1 будет выставлен диспетчером до msg2. То, что на самом деле происходит после их установки, действительно зависит от того, какой диспетчер вы используете: http://akka.io/docs/akka/1.1.2/scala/dispatchers.html, но в вашем случае тогда, пока B может принять оба сообщения затем всегда будут получать msg1 перед сообщением msg2.

Для (2), нет, у вас нет этой гарантии.! метод возвращает, как только диспетчер завершает сообщение не тогда, когда сообщение принимается почтовым ящиком целевого актива. Посылка затем выполняется в другом потоке и подчиняется всем условиям гонки.

Сообщение отправлено! оператора через сеть по-настоящему асинхронно или он ждет, пока получающий почтовый ящик не получит его?

Вы можете использовать BoundedMailbox с локальными участниками, чтобы показать, что передача сообщений диспетчерам асинхронна с помощью::

class TestActor extends Actor {
  val mailboxCapacity = BoundedMailbox(capacity = 1)
  self.dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("test", 1, mailboxCapacity).build

  def receive = {
    case x: String => 
      Thread.sleep(1000)
      println("Received message")
    case _ => 
  }
}

val t = Actor.actorOf[TestActor]
t.start()

t ! "one"; t ! "two"; t ! "three"; println("Main thread");

Печать

scala>     t ! "one"; t ! "two"; t ! "three"; println("Main thread");
Received message
Main thread

scala> Received message
Received message

Это означает, что выполнение кода в основном потоке продолжается до того, как вы даже узнаете, будет ли сообщение когда-либо доставлено. В этом случае отправка сообщения может быть легко выполнена, если мы установим pushTimeout в диспетчере и сделаем Thread.sleep более длинным, чем таймаут.

Сравните это с использованием!!:

scala>     t !! "one"; t !! "two"; t !! "three"; println("test");
Received message
Received message
Received message
test

Итак, имея это в виду. Способ достижения (2):

case msg1 =>
  cRef !! msg3
  aRef ! msg4 

Ответ 2

Эрланг дает вам первую гарантию, но не вторую. Акка также может дать вам первую гарантию, но она не даст вам второй гарантии.

Я не знаю ответа на ваш следующий вопрос.