Actor의 react와 receive

Posted 2010.08.08 00:07
Actor의 개념도 생소하지만, 특히 메시지 수신에 사용하는 reactor, receive 메서드는 헷갈리기 쉬운 듯합니다. stackoverflow에 일목요연하게 정리된 답변이 올라와 번역한 뒤 설명을 추가해 봤습니다. 스터디에서 해당 링크를 알려준 명수 맏형께도 감사합니다. 도움이 되었으면 좋겠군요. 본문에서는 존칭을 생략합니다.
 Actor의 기본적인 내용을 알고 있다고 가정하고, 메세지 수신에 사용되는 receive, react 두 개의 메서드를 비교해본다.

First, each actor waiting on receive is occupying a thread. If it never receives anything, that thread will never do anything. An actor on react does not occupy any thread until it receives something. Once it receives something, a thread gets allocated to it, and it is initialized in it.

Now, the initialization part is important. A receiving thread is expected to return something, a reacting thread is not. So the previous stack state at the end of the last react can be, and is, wholly discarded. Not needing to either save or restore the stack state makes the thread faster to start.

There are various performance reasons why you might want one or other. As you know, having too many threads in Java is not a good idea. On the other hand, because you have to attach an actor to a thread before it can react, it is faster to receive a message than react to it. So if you have actors that receive many messages but do very little with it, the additional delay of react might make it too slow for your purposes.
우선 receive로 동작하는 Actor 는 하나의 스레드를 차지한다. 만일 어떠한 메시지도 수신하지 않는다면, 해당 스레드는 아무 것도 하지 않을 것이다. 반면 react에 기반한 Actor는 메시지를 수신하기 전까지는 스레드를 차지하지 않는다. 메시지를 수신하면 비로소 스레드가 할당되고, 초기화를 수행한다.

초기화는 중요한 부분이다. receive를 사용하는 스레드는 무언가를 리턴한다고 가정하지만, react를 사용하는 스레드는 리턴을 아예 하지 않는다고 가정한다.

그렇다면 왜 두 가지 선택 사항이 존재하는가? 여기에는 성능과 관련된 여러 이유가 있다. 알고 있듯이, 자바에서 많은 스레드를 사용하는 것은 좋은 방법이 아니다. 하지만 react 기반의 actor는 react 수행 전 actor를 할당해야 하기 때문에, receive를 사용하는 쪽이 react를 사용하는 것보다 속도가 빠르다. 만일 많은 메세지를 수신하는데, 수신한 메시지를 기반으로 아주 작은 일만을 수행한다면, react에서 발생하는 추가적인 delay는 성능저하를 일으킬 수도 있다. 

 두 메서드는 일단 메서드의 반환 타입부터가 다르다. 특히 react는 다음과 같이 정의되어 있다.
def react(f : scala.PartialFunction[scala.Any, scala.Unit]) : scala.Nothing
 메서드가 Nothing 타입을 반환한다는 사실의 의미를 생각해보자. Nothing은 bottom type이기 때문에 Nothing을 상속한 서브 클래스는 존재할 수 없으며, Nothing 자체를 반환하려고 해도 abstract 클래스이기 때문에 불가능하다. 따라서 react 메서드는 값을 반환할 수 없고, react 내부에서는 예외를 발생시키거나 무한히 실행해야 한다. 애당초 react 메서드는 메서드를 종료하지 못해 해당 스레드를 유지할 수 밖에 없는 불쌍한(?) 운명인 것이다.

다음 코드를 실행해보자. react 종료 후 println("message processed!")는 수행되지 않는다. 물론 react대신 receive를 사용하면 이야기는 달라진다.
import scala.actors.Actor._

actor { 
  loop { 
    react { 
      case any => println(any) 
    } 
    println("message processed!"); 
}}
참고로 Actor.actor 메서드는 Actor를 생성하고 즉시 수행한다. 


« PREV : 1 : 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : NEXT »