我开始使用Scala和AKKA模式,我已经编写了这段代码,但它不起作用,我不知道为什么......
我创建了一个从控制台读取用户输入的小项目。 当这个用户写了一个'关键字'时,keyWord Actor(Child)会解释它并与控制台Actor(Grand parent)进行通信。
动作演员将用于广播和做更多的事情。
当我在控制台Actor中输入命令'rename'时,我进入动作Actor,然后在keyWord Actor中输入并重命名方法,但之后没有,我没有进入重命名方法在控制台上的演员。
你能帮助我吗?
如果你看到任何错误的实践,请不要告诉我如何解决这个问题:)。
谢谢!
主要
import ConsoleActor._
import akka.actor.ActorSystem
object Main extends App {
val system = ActorSystem("My-Little-IRC")
val consoleActor = system.actorOf(ConsoleActor.props, "consoleActor")
consoleActor ! ReadConsoleInput
system.terminate()
}
consoleActor
import ActionActor.TreatInputUser
import akka.actor.{Actor, Props}
import scala.io.StdIn
object ConsoleActor {
case class ReadConsoleInput()
case class StopLoop()
case class Rename()
case class WhoIAm()
def props = Props[ConsoleActor]
}
class ConsoleActor() extends Actor {
val keyWordActor = context.actorOf(KeyWordActor.props(this.self), "keyWordActor")
val actionActor = context.actorOf(ActionActor.props(keyWordActor), "actionActor")
var currentUser: String = ""
var loop: Boolean = true;
import ConsoleActor._
def isValidString( str: String ): Boolean = {
var isValid: Boolean = false
if (str != null && !str.trim().isEmpty)
isValid = true
isValid
}
def initiatePresentation( ) = {
println("Hi ! Who are you ?")
currentUser = StdIn.readLine()
println(s"Nice to meet you ${currentUser}, I'm your console app !")
}
def receive = {
case ReadConsoleInput => {
initiatePresentation
var value = ""
while (loop) {
println("Yes ?")
value = StdIn.readLine()
if (isValidString(value)) {
actionActor ! TreatInputUser(value)
}
}
}
case StopLoop => {
println("stop Loooop !")
loop = false
}
case Rename => {
println(s"${currentUser} was a good name ! Which is your new name ?")
currentUser = StdIn.readLine()
println(s"Nice to meet you -again- ${currentUser}")
}
case WhoIAm =>{
println(s"I'm ${currentUser}")
}
}
}
actionActor
import ActionActor.TreatInputUser
import akka.actor.{Actor, ActorRef, Props}
import akka.util.Timeout
import scala.concurrent.duration._
import akka.pattern.ask
import scala.concurrent.Await
object ActionActor {
case class TreatInputUser(string: String)
def props(keyWordActor: ActorRef) = Props(new ActionActor(keyWordActor))
}
class ActionActor(keyWordActor: ActorRef) extends Actor {
import KeyWordActor._
def receive = {
case TreatInputUser(string) => {
implicit val timeout = Timeout(5 seconds)
var isKeyWord = keyWordActor ? IsKeyWord(string)
val isKeyWordResult = Await.result(isKeyWord, timeout.duration).asInstanceOf[ Boolean ]
println(isKeyWordResult)
if (isKeyWordResult) {
keyWordActor ! HandleKeyWord(string)
}
else {
println("bla bla bla")
}
}
}
}
keyWord actor
import ConsoleActor.{Rename, StopLoop, WhoIAm}
import akka.actor.{Actor, ActorRef, Props}
object KeyWordActor {
case class IsKeyWord(key : String)
case class HandleKeyWord(key : String)
def props(consoleActor: ActorRef) = Props(new KeyWordActor(consoleActor))
}
class KeyWordActor(consoleActor: ActorRef) extends Actor {
import KeyWordActor._
val KeysWord : Map[ String, ()=> Any] = Map("rename" -> renameFunction, "stop" -> stopFunction, "42" -> uselessfunction, "john doe ?" -> AmIJohnDoe)
def renameFunction() = {
println("here")
consoleActor ! Rename
}
def stopFunction() = {
consoleActor ! StopLoop
}
def uselessfunction() = {
println("useless")
}
def AmIJohnDoe() ={
consoleActor ! WhoIAm
}
def receive = {
case IsKeyWord(key) => {
sender ! KeysWord.contains(key.toLowerCase)
}
case HandleKeyWord(key) => {
if (KeysWord.contains(key.toLowerCase)) {
KeysWord(key.toLowerCase)()
}
}
}
}
答案 0 :(得分:2)
您不得阻止使用receive
方法。您编写它的方式(使用while
循环),初始ReadConsoleInput
消息永远不会完成处理,并且任何后续消息(如StopLoop
)将永远不会在Actor邮箱中保持不变。 / p>
如果您必须有选择地阅读StdIn
(而不是继续阅读例如您的Main
课程),那么一种方法可能是更改您的ConsoleActor
,以便在收到时ReadConsoleInput
StdIn.readLine
消息,只需尝试ActionActor
一次,然后将结果转发给StdIn.readLine
。由于import akka.pattern.pipe
import scala.concurrent.Future
//...
def receive = {
case ReadConsoleInput =>
import context.dispatcher //provide a thread pool to do async work
Future(StdIn.readLine()) //read a line of input asynchronously
.filter(isValidString) //only continue if line is valid
.map(TreatInputUser) //wrap the (valid) String in a message
.pipeTo(actionActor) //forward it
case Rename => ...
}
调用本身也是阻塞的,因此您应该异步执行。 " pipe"模式在这里派上用场:
ConsoleActor
这样,ActionActor
立即再次可用于处理新邮件,而只要用户在控制台中输入一行,TreatInputUser
就会收到ActionActor
消息。
您可以在Await
内应用相同的模式,而不是依赖StdIn.readLine
。
如果您想关闭循环以便继续发送消息,我可以使用behaviour确保两个Highcharts.chart('container', {
title: { text: 'Linked Series'},
series: [{
id: 2,
data: [3, 1, 3, 2]
}, {
id: 0,
data: [2, 3, 2, 1]
}, {
id: 1,
linkedTo: 2,
data: [1, 2, 1, 3]
}, ]
});
来电不会干扰。