2017-10-11 2 views
1

스칼라와 AKKA 패턴을 사용하기 시작했습니다.이 코드를 작성했지만 작동하지 않고 이유를 모르겠습니다 ...Akka에서는 StdIn에서 읽는 것과 같이 메소드 호출을 차단하는 것을 어떻게 관리합니까?

사용자를 읽는 작은 프로젝트를 만들었습니다. 콘솔로부터의 입력. 이 사용자가 '키워드'를 작성하면 keyWord Actor (Child)가이를 해석하고 Console Actor (Grand 부모)와 통신합니다.

조치 액터는 방송하고 더 많은 작업을 수행하는 데 사용됩니다.

콘솔 액터에서 'rename'명령을 입력 할 때, 나는 Actor 액터와 그 이후에 keyWord Actor에 입력하고 Rename Method에 입력합니다.하지만 그 이후에는 아무 것도 입력하지 않았습니다. 메서드를 호출합니다.

도와 주시겠습니까?

틀린 설명을 본 사람은 저에게 해결 방법을 알려주지 마십시오. :)

감사합니다.

홈페이지

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") 
     } 
    } 
    } 
} 

키워드 배우

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)() 
     } 
    } 
    } 
} 
+1

'ConsoleActor'에서, 당신은 당신의'receive' 메소드를 차단하고 있습니다.[차단하려면 신중한 관리가 필요합니다.] (https://doc.akka.io/docs/akka/2.5/scala/dispatchers.html#blocking-needs-careful-management). 오히려,'Main'에서'StdIn'을 읽고, 행을 읽을 때'ConsoleActor' (또는 누군가 적절한)에게 메시지를 보냅니다. –

+0

안녕하세요 @ LászlóvandenHoek, 내가 '기본'으로 사용자 입력을 읽어야한다고 말했을 때 '기본'루프에 'While'루프가 있어야한다는 것을 의미합니까? 그렇다면 'keyWord'배우가 루프를 멈출 수있는 방법은 무엇입니까? – Brice

+0

내 이전의 의견은 의미하지만 이제는 내가 당신의 질문을 완전히 이해 했으므로 대답을주었습니다. –

답변

2

receive 방법으로 차단하면 안됩니다. (while 루프로) 작성한대로 초기 ReadConsoleInput 메시지는 처리가 완료되지 않으며 이후의 모든 메시지 (예 : StopLoop)는 액터 메일함에 영원히 남습니다. 당신은 선택적으로 (반대 그냥 계속 예에 Main 클래스를 읽기 위해) 다음 하나의 접근 방식은 변경 될 수 StdIn에서 읽을해야하는 경우

당신의 ConsoleActor 그래서이 ReadConsoleInput 메시지를 수신 할 때, 그냥 StdIn.readLine을하려고해야 번으로 입력 한 다음 결과를 ActionActor으로 전달하십시오. StdIn.readLine 호출 자체도 차단되므로 비동기 적으로 수행해야합니다. 은 "pipe"패턴은 여기에 유용 : 사용자가 콘솔에서 줄을 입력 완료 할 때마다 ActionActorTreatInputUser 메시지가 나타납니다 동안

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 => ... 
} 

이 방법은 ConsoleActor 즉시 다시 새 메시지를 처리하는 데 사용할 수 있습니다.

Await 대신에 ActionActor 안에 동일한 패턴을 적용 할 수 있습니다.

메시지를 계속 보낼 수 있도록 루프를 닫으려면 behaviour을 사용하여 두 개의 StdIn.readLine 호출이 간섭하지 않는지 확인하십시오.

+0

이제 'console Actor'에 접근 할 수 있습니다. 'keyWord Actor'감사합니다! 하지만 지금은 한 명령 만 쓸 수 있습니다. 하나 이상의 명령을 쓸 수있는 가능성을 잃어 버렸습니다. 하나 이상의 명령을 쓸 수있게 변경해야 할 사항은 무엇입니까? – Brice

관련 문제