actor model: one actor requires information from another actor
Something I don't understand about the actor model is this. Suppose you have two actors. They collect and manage data from various sources. These sources interact with the actors via their inbox/postbox/queue. For example actor A collects signals while actor B manages information about the system as a whole.
At some point actor A has to process its data. While it's processing, it can't do much else. New signals can't be processed, for example. As part of the data processing, actor A needs information from actor B before A can continue.
In pseudo code:
functionOfActorA()
{
internalQueue {
...doing stuff with our data
info = actor_B.getInfo() -> what should happen here?
...doing stuf with our data and the obtained info
}
}
getInfo()//function of actor B
{
internalQueue {
...prepare requested info
... -> what should happen here?
}
}
If both actors should operate independently on their own queue or thread, then how can you get info from one actor to another upon request of an actor?
Actor A can request information by sending a request to Actor B, but the response will come back in a message, which Actor A will receive at some future point. There are two ways of saving this information:
Actor A can store the information internally to wait for that response.
Actor A can attach the information to the message it sends to Actor B, and Actor B returns that context (that it otherwise ignores).
When Actor A gets the information from Actor B, it can then resume processing.
Here's an example of the first style of implementation, using the Thespian Python actor library (http://thespianpy.com):
class ActorA(Actor):
def __init__(self, *args, **kw):
super(ActorA, self).__init__(args, kw)
self.datalist = []
def receiveMessage(self, msg, sender):
if isinstance(msg, ActorAddress):
self.actorB = msg
elif isinstance(msg, WorkRequest):
x = got_some_data(msg)
self.datalist.append(x)
self.send(self.actorB, NeedInfo())
elif isinstance(msg, Info):
x = self.datalist.pop()
process_data(x, msg)
class ActorB(Actor):
def receiveMessage(self, msg, sender):
if isinstance(msg, NeedInfo):
i = get_info(msg)
self.send(sender, i)
The above shows the basic functionality for storing the work internally to the actor to be continued later. There are a few considerations:
If there are multiple data items to be stored, ActorA needs to have some way of determining which item the information from ActorB applies to.
ActorA needs to handle the case where it doesn't know ActorB's address yet.
ActorA should probably use some kind of timeout to avoid keeping work on its internal list forever (if somehow ActorB never responds).
If ActorA exits or dies, it should do something appropriate with the items still on datalist before exiting.
Here's the corresponding simple example for the second implementation style:
class ActorA(Actor):
def receiveMessage(self, msg, sender):
if isinstance(msg, ActorAddress):
self.actorB = msg
elif isinstance(msg, WorkRequest):
x = got_some_data(msg)
self.send(self.actorB, NeedInfo(x))
elif isinstance(msg, Info):
x = msg.orig_request.data
process_data(x, msg)
class ActorB(Actor):
def receiveMessage(self, msg, sender):
if isinstance(msg, NeedInfo):
i = getinfo(msg)
i.orig_request = msg
self.send(sender, i)
In this second example the call to create NeedInfo stores the data in the .data
field of the NeedInfo object, and the Info passed back by ActorB has the original NeedInfo message attached to it. Considerations for this style are:
No need to independently correlate original WorkRequest messages to the corresponding Info because they are attached to each other.
ActorA has more dependence on the implementation of ActorB to expect ActorB to attach the original message to its response to allow ActorA to recover this context.
ActorA still needs to handle the case where it doesn't know ActorB's address yet.
If ActorA exits or dies, it doesn't have a record of this outstanding work to take any action before cleanup (although the Dead Letter handler can perform this role).
The above examples are fairly simplistic, and there will be some variation for other Actor Model library implementations, but these general techniques should broadly apply regardless of library/language. Both of these implementation styles follow the general Actor guideline of:
On receipt of message, do what work is possible
Update internal state as needed for handling the next message
Exit from the message handler
While it is possible to write an Actor that does a blocking operation, that operation will interfere with the Actor's responsiveness and ability to handle other messages (as you properly noted), so wherever possible use a message-driven continuation instead of a blocking call.
链接地址: http://www.djcxy.com/p/21520.html上一篇: “双重散列”密码不仅仅是一次散列吗?