관리 메뉴

HAMA 블로그

예제로 보는 아카(akka) - 7. 상태머신 ( 상태에 따른 행동변화 ) 본문

Akka

예제로 보는 아카(akka) - 7. 상태머신 ( 상태에 따른 행동변화 )

[하마] 이승현 (wowlsh93@gmail.com) 2016. 10. 6. 20:56

- Scala 2.11 기반 

- Akka 2.4.11 기반 

Learning Concurrent Programming in Scala 참고 


상태머신 (상태에 따른 행동변화 )

- 액터가 자신의 상태를 바꿈에 따라 메세지를 처리하는 방식도 달라 진다.
- 아카 액터에서 receive 메소드 안에 상태에 따른 여러 행위를 넣는것은 바람직 하지 않다.

class CountdownActor extends Actor {
var n = 10
def receive = if (n > 0 ) {     case "count" => ...do somthing .. n -=1

} else PartialFunction.empty
}

- n 이 0 보다 클 경우에는 어떤 행동을 하고 
- n 이 0 일때는 아무것도 안한다.
- receive 함수를 보면  if 문을 통해 부분함수가 다르게 반환된다. 이렇게 하면 안된다.!!

상태에 따른 행위를 애초에 나누어서 처리 해야하는데,  그때 become 이 사용된다. 코드를 살펴보자.

become

class CountdownActor extends Actor {
var n = 10
def counting: Actor.Receive = {
case "count" =>
n -= 1
log(s"n = $n")
if (n == 0) context.become(done)
}
def done = PartialFunction.empty
def receive = counting
}

- 초기 receive 메소드에 counting 이라는  메소드를 지정했다. 즉 초기 상태에 매핑되는 메소드가  counting 
- 액터의 상태가 n=0 으로 바뀌면 context.become(done) 을 이용해서 매핑되는 메소드도 done으로 바꿈.

예제 )


class DictionaryActor extends Actor {
private val log = Logging(context.system, this)
private val dictionary = mutable.Set[String]()
def receive = uninitialized
def uninitialized: PartialFunction[Any, Unit] = {
case DictionaryActor.Init(path) =>
val stream = getClass.getResourceAsStream(path)
val words = Source.fromInputStream(stream)
for (w <- words.getLines) dictionary += w
context.become(initialized)
}
def initialized: PartialFunction[Any, Unit] = {
case DictionaryActor.IsWord(w) =>
log.info(s"word '$w' exists: ${dictionary(w)}")
case DictionaryActor.End =>
dictionary.clear()
context.become(uninitialized)
}
override def unhandled(msg: Any) = {
log.info(s"message $msg should not be sent in this state.")
}
}


object DictionaryActor {
case class Init(path: String)
case class IsWord(w: String)
case object End
}


object ActorsBecome extends App {
val dict = ourSystem.actorOf(Props[DictionaryActor], "dictionary")
dict ! DictionaryActor.IsWord("program")
Thread.sleep(1000)
dict ! DictionaryActor.Init("/org/learningconcurrency/words.txt")
Thread.sleep(1000)
dict ! DictionaryActor.IsWord("program")
Thread.sleep(1000)
dict ! DictionaryActor.IsWord("balaban")
Thread.sleep(1000)
dict ! DictionaryActor.End
Thread.sleep(1000)
dict ! DictionaryActor.IsWord("termination")
Thread.sleep(1000)
ourSystem.shutdown()
}

- uninitialized 로 초기상태 에서 Init 가 호출되어 초기화가 완료되면 initialized  로 상태를 바꿈.
initialized  상태 에서는 IsWord 메세지를 받아서 작업을 함.  작업 끝을 알리는 메세지를 받으면 uninitialized 로 행동을 다시바꿈. 



Comments