Multithreading 在Scala演员中整合自主和反应行为的最佳方式?
我是一名经验丰富的Java程序员,现在开始开发基于actor的Scala应用程序。在我目前正在开发的一个应用程序中,我必须处理一个发送方参与者的实现,该发送方参与者表现出自治和反应行为。场景如下(伪代码): 我的问题是:对于需要集成自治性和反应性(如上所述)的Scala参与者来说,哪种方式是表达自治行为的最佳方式? 换句话说,在上面的示例中,哪种方式/风格是编写发送方参与者代码的最佳方式/风格 我提出了一个解决方案(如下所述),但由于我不是scala大师(现在:),我想知道我所实现的是否可以在更好/更好的解决方案中得到改进Multithreading 在Scala演员中整合自主和反应行为的最佳方式?,multithreading,scala,asynchronous,actor,event-based-programming,Multithreading,Scala,Asynchronous,Actor,Event Based Programming,我是一名经验丰富的Java程序员,现在开始开发基于actor的Scala应用程序。在我目前正在开发的一个应用程序中,我必须处理一个发送方参与者的实现,该发送方参与者表现出自治和反应行为。场景如下(伪代码): 我的问题是:对于需要集成自治性和反应性(如上所述)的Scala参与者来说,哪种方式是表达自治行为的最佳方式? 换句话说,在上面的示例中,哪种方式/风格是编写发送方参与者代码的最佳方式/风格 我提出了一个解决方案(如下所述),但由于我不是scala大师(现在:),我想知道我所实现的是否可以在更
case object START
case object A
case object B
case object C
case object SENT_A
case object SENT_B
case object ACK_A
case object ACK_B
case object ACK_C
case object STOP
class Sender(stdout: Stdout) extends Actor {
def act() {
self!START
while (true){
receive {
case START =>
stdout!?A
self!SENT_A
case SENT_A =>
stdout!?B
self!SENT_B
case SENT_B =>
stdout!?C
stdout!?STOP
exit()
case STOP => {
Console.println("[Sender:]Received STOP, terminating")
stdout!?STOP
exit()
}
}
}
}
}
class Stdout() extends Actor {
def act() {
while (true) {
receive{
case A =>
Console.println("[Stdout:]A")
reply(ACK_A)
case B =>
Console.println("[Stdout:]B")
reply(ACK_B)
case C =>
Console.println("[Stdout:]C")
reply(ACK_C)
exit()
case STOP =>
Console.println("[Stdout:]Received STOP, terminating")
exit()
}
}
}
}
class StopNotifier(sender: Sender) extends Actor {
def act() {
/*
* The idea is that the StopNotifier should send a STOP message to the Sender
* when a certain condition is met.
* The sleep used here is just a semplification, since the detection of such
* a condition is not relevant for the example.
*/
Thread.sleep(200)
Console.println("[StopNotifier:]Sending STOP to sender")
sender ! STOP
exit()
}
}
object app extends Application {
val stdout = new Stdout
stdout.start
val sender = new Sender(stdout)
sender.start
val stopNotifier = new StopNotifier(sender)
stopNotifier.start
}
在我当前的实现中特别困扰我的是这样一个事实:为了能够对从StopNotifier接收到的STOP消息做出迅速反应,我需要在发送方的每个执行步骤中自我发送消息(即,在将A、B发送给Stdout actor之后)。在我看来,做这些事情的正确方式太难了:)
我还尝试使用其他scala语言构造(例如异步发送、响应等)开发其他解决方案,但在某种程度上,它们似乎会影响到其他问题/技巧
是否有人有更好的解决方案来处理scala actors中自治和反应行为的集成?如果我理解正确,您应该使用Akka actors,特别是Akka FSM,将发送方建模为状态机。Akka参与者有一个内置的停止机制,或者您可以始终使用自己的消息,当未处理时,可以通过
处理程序从所有状态处理这些消息
看
这显然是过火了,但我想你是想做更复杂的事情。您还可以使用Stdout
“监视”Sender
,使其在Sender
终止时终止,而不是在收到特定消息时终止。看
无论您如何在发送方中实现状态,如果您想使用参与者对其进行建模,我相信您将需要“自发送”消息,无论是在事件处理中,还是在我上面提到的计时器中。从一个react或receive块中的一个参与者按顺序发送的消息都将按该顺序接收。(你可能会有来自其他演员的其他消息散布,但你不会先发送A,然后发送B,然后发送A。)
所以你可以
stdout ! A
stdout ! B
stdout ! C
除非你还需要做别的事情。是的,我知道。但是在实际应用程序中,我需要按顺序检索回复(这就是为什么我使用!?)。此外,如问题中所述,我需要将这种主动行为与从StopNotifier接收stop相关联的被动行为结合起来。@the_dark_destructor-!?是同步的——在得到回复之前,你不会从那一点开始传递,所以你无论如何也不能对停止做出如此迅速的响应。如果可以等一个,为什么不能等三个呢?我明白了。。。我肯定会有一个更好的看阿卡FSM的演员然后(我不知道阿卡)。然而,在您的回复之后,我觉得我采用的基于scala的解决方案最适合解决此类问题,对吗?正如你所说,“自我发送”消息成为强制性的,以实现自治行为和反应行为之间的那种集成。@u dark_析构函数这个问题可能太开放了。如果您需要并发性,那么Akka演员可能是最佳选择。不过,这可能有点过头了。请注意,我没有意识到您需要对stdout的调用是同步的。这让我相信这是过分的。您应该使用?
而不是代码>以找回未来。
package fsmTest
import akka.actor._
import akka.util.duration._
sealed trait Msg
case object A extends Msg
case object B extends Msg
case object C extends Msg
sealed trait SenderState
case object Started extends SenderState
case object SentA extends SenderState
case object SentB extends SenderState
case class SenderData()
class Sender(stdout: ActorRef)
extends Actor
with FSM[SenderState, SenderData] {
case object GoNextState
startWith(Started, SenderData())
when(Started) {
case Event(GoNextState, data) => {
stdout ! A
goto(SentA) using data
}
}
when(SentA) {
case Event(GoNextState, data) => {
stdout ! B
goto(SentB) using data
}
}
when(SentB) {
case Event(GoNextState, data) => {
stdout ! C
goto(Started) using data
}
}
// //Handle messages which aren't explicitly handled in state here
// whenUnhandled {
// case Event(SomeCustomStop, data) => {
// stop(FSM.Shutdown)
// }
// }
setTimer("goNextState", GoNextState, 1 second, repeat = true)
initialize
}
class Stdout() extends Actor {
def receive = {
case msg: Msg => {
context.watch(sender) //Not sure if you're gonna want to do this here, but you get the point
println(msg)
}
case Terminated(_) => context.stop(self)
}
}
object FSMTest extends App {
implicit val system = ActorSystem("Testing")
val stdout = system.actorOf(Props[Stdout], "stdout")
val sender = system.actorOf(Props(new Sender(stdout)), "sender")
system.scheduler.scheduleOnce(5 seconds) {
system.stop(sender)
system.shutdown()
}
system.awaitTermination(10 seconds)
}
stdout ! A
stdout ! B
stdout ! C