临时保存发件人以便稍后回复
我有3个演员
class Actor1 extends Actor {
val actor2 = context actorOf (Props[Actor2])
actor2 ! Actor2Request
def receive = {
case data: String => // need to receive it
}
}
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
//sender is Actor1 but I want to save it now and reply it later on in "case DoneActor3(data: String)"
val actor3 = context actorOf (Props[Actor3])
actor3 ! Actor3Request
case DoneActor3(data: String) =>
// doing something with data
// and then send it to Actor1
sender ! data //ops! sender is Actor3 now, not Actor1!
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request =>
//doing some work...
sender ! DoneActor3(data) // sender is Actor2 and that's ok!
}
}
查看Actor2
代码,我希望在收到sender
消息时保存Actor2Request
( Actor1 )并回复此sender
} Actor2
收到DoneActor3(data: String)
消息后。
有没有惯用的方法呢?
答案 0 :(得分:2)
使用forward
,在演员之间传递消息时保留原始发件人。
在这种情况下,您甚至不需要通过Actor2
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
//sender will still be actor1 when actor3 receives this forwarded message
actor3 forward Actor3Request
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request =>
//doing some work...
sender ! data // sender is actor1
}
}
如果你做需要通过Actor2
返回,也许是为了进行一些中间处理,那么你想捕获原始发件人并通过actor消息传递它:
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
//sender at this point is actor1
actor3 ! Actor3Request(sender)
case DoneActor3(origin, data) =>
// Do some other stuff here
origin ! data //origin is the original sender as passed to Actor3Request
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request(origin) =>
//doing some work...
sender ! DoneActor3(origin, data) // origin is actor1, sender is actor2
}
}
或者你可以混合使用匹配这些技巧,让Actor3
直接向origin
<强>更新强>
有一个最终解决方案,此处有效,因为actor2
由actor1
创建。在这种情况下,我们知道actor1
将成为监督层次结构中actor2
的父级:
class Actor2 extends Actor {
def receive = {
case Actor2Request =>
val actor3 = context actorOf (Props[Actor3])
actor3 ! Actor3Request
case DoneActor3(data) =>
// Do some other stuff here
context.parent ! data //context.parent is actor1
}
}
class Actor3 extends Actor {
def receive = {
case Actor3Request =>
//doing some work...
sender ! DoneActor3(data) //sender is actor2
}
}
答案 1 :(得分:0)
只需将ActorRef
保存在var
中,稍后再使用:
class Actor2 extends Actor {
private var requester: ActorRef = _
def receive = {
case Actor2Request =>
requester = sender
val actor3 = context actorOf (Props[Actor3])
actor3 ! Actor3Request
case DoneActor3(data: String) =>
requester ! data
}
}
这就是演员的目的,跟踪不断变化的状态。我知道Scala不鼓励使用var
,但在演员的背景下它完全没问题。
修改评论:您的Actor2
是在Actor1
中创建的,它们之间存在一对一的关联,因此,即使您有多个Actor1
个实例,每个人都有自己的孩子Actor2
。我不知道您对此设计的目标是什么,另一种方法是用户parent
而不是sender
中的Actor2
,这将指向创建的Actor1
它,或者你可以传递ActorRef
的{{1}}作为Actor1
的构造函数的参数。