Message delivery sequence in akka actors
I'm pretty new to Akka and couldn't find the answer in the reference manual.
Suppose we have remote actors distribut开发者_Python百科ed in the cluster of 3 machines (A, B, C), where one actor lives on each machine and others have actorRef to 2 others, i.e.:
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)
Actor A executes following code:
bRef ! msg1
bRef ! msg2
Actor B executes following code in message handler:
case msg1 =>
cRef ! msg3
aRef ! msg4
Actor C executes following code in message handler:
case msg3 =>
aRef ! msg5
Can I make the following assumptions (if any):
actor B gets msg1 before it gets msg2
actor A gets msg5 before it gets msg4
And the follow-up question which probably leads to understanding the above: Is message sent by the ! operator through the network truly asynchronously or does it wait until the receiving mailbox gets it? I.e. does the line
bRef ! msg1
block until actor B gets the message in its mailbox or does it spawn the thread which handles the delivery and continue executing
bRef ! msg2
before it even knows that actor B got msg1?
For (1) you have the guarantee that msg1 will be enqueued by the dispatcher before msg2. What actually happens once they are enqueued is really dependent on which dispatcher you use: http://akka.io/docs/akka/1.1.2/scala/dispatchers.html, but in your case then so long as B can accept both messages then it will always receive msg1 before msg2.
For (2), no you do not have this guarantee. The ! method returns as soon as the dispatcher enqueues the message not when the message is accepted by the target actor's mailbox. The sending is then done in another thread and is subject to all kinds of race conditions.
Is message sent by the ! operator through the network truly asynchronously or does it wait until the receiving mailbox gets it?
You can use a BoundedMailbox with local actors to show that enqueuing messages to dispatchers is asynchronous with !:
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");
Prints:
scala> t ! "one"; t ! "two"; t ! "three"; println("Main thread");
Received message
Main thread
scala> Received message
Received message
Which means that code execution in the main thread continues before you even know whether or not the message will ever be delivered. In this case the message send could easily have timed out if we set a pushTimeout on the dispatcher and made Thread.sleep wait for longer than the timeout.
Compare this to using !!:
scala> t !! "one"; t !! "two"; t !! "three"; println("test");
Received message
Received message
Received message
test
So, with this in mind. The way to achieve (2) would be:
case msg1 =>
cRef !! msg3
aRef ! msg4
Erlang gives you the first guarantee, but not the second. Akka might give you the first guarantee as well, but it will certainly not give you the second guarantee.
I don't know the answer to your follow up question.
精彩评论