2009-06-17 4 views
27

The reply 내 최근 질문에 따르면 한 배우가 자신의 메시지를 한 번에 하나씩 개 처리했습니다.. 사실입니까? 나는 명시 적으로 다음 코드가 포함되어, 그 (스칼라에서의 프로그래밍)라고 아무것도 볼 (PP를. 593)Scala 액터는 여러 메시지를 동시에 처리 할 수 ​​있습니까?

가 [react 방법] 처리 할 수있는 메시지를 발견하면, [가] 것입니다 나중에 실행하기에 대한 해당 메시지 의 처리를 예약하고 예외

(강조 내 자신을) 던져. 두 관련 (상호 배타적) 질문 : simulatenously을 여러 메시지를 처리 ​​할 수있는 배우를 가정

  1. , 어떻게 내가 (이 내가하고자하는 것입니다 경우) 한 번에 메시지 하나를 처리하기 위해 배우를 강제 할 수 있습니까? (receive를 사용하고 계십니까?) 배우를 가정
  2. 메시지를 한 번에 하나씩 처리, 내가 가장 사실 가 할 수 프로세스 메시지를 동시에

편집 배우 구현하는 것이 방법 :하고 테스트의 비트가 보인다을 내가 틀렸다는 것과 그 배우들이 실제로 순차적이라는 것을 알 수 있습니다. 질문 2 : 답변이 필요합니다.

+5

이 질문이 어떻게 하향식을 정당화하는지 보지 못합니다. 스칼라에서 프로그래밍의 배우에 대한 전체 장을 읽고 대답을 확신 할 수 없다면 이는 완전히 유효한 질문입니다. –

+0

액터를 사용하여 공유 리소스에 대한 액세스를 중재 할 수 있고 공유 리소스에 대한 다른 동기화는 필요하지 않기 때문에 단일 액터가 메시지를 순차적으로 처리합니다.메시지를 순차적으로 처리 할 수있는 경우 동기화 오류가 발생하지 않도록 배우 내부에서 잠금을 사용해야합니다. –

답변

26

배우가 한 번에 하나의 메시지를 처리합니다. 여러 메시지를 처리하는 고전적인 패턴은 소비자 행위자 풀에 대해 하나의 코디네이터 액터를 배치하는 것입니다. react를 사용하면 소비자 풀은 클 수 있지만 여전히 적은 수의 JVM 스레드 만 사용합니다. 여기에 10 명의 소비자 풀과 하나의 코디네이터를 만드는 예가 있습니다.

import scala.actors.Actor 
import scala.actors.Actor._ 

case class Request(sender : Actor, payload : String) 
case class Ready(sender : Actor) 
case class Result(result : String) 
case object Stop 

def consumer(n : Int) = actor { 
    loop { 
    react { 
     case Ready(sender) => 
     sender ! Ready(self) 
     case Request(sender, payload) => 
     println("request to consumer " + n + " with " + payload) 
     // some silly computation so the process takes awhile 
     val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString 
     sender ! Result(result) 
     println("consumer " + n + " is done processing " + result) 
     case Stop => exit 
    } 
    } 
} 

// a pool of 10 consumers 
val consumers = for (n <- 0 to 10) yield consumer(n) 

val coordinator = actor { 
    loop { 
    react { 
     case msg @ Request(sender, payload) => 
      consumers foreach {_ ! Ready(self)} 
      react { 
       // send the request to the first available consumer 
       case Ready(consumer) => consumer ! msg 
      } 
     case Stop => 
      consumers foreach {_ ! Stop} 
      exit 
    } 
    } 
} 

// a little test loop - note that it's not doing anything with the results or telling the coordinator to stop 
for (i <- 0 to 1000) coordinator ! Request(self, i.toString) 

이 코드는 사용 가능한 소비자를 확인하고 해당 소비자에게 요청을 보냅니다. 대안은 무작위로 소비자에게 할당하거나 라운드 로빈 스케줄러를 사용하는 것입니다.

당신이하는 일에 따라 Scala 's Futures를 사용하는 것이 더 나을 것입니다. 예를 들어, 배우가 실제로 필요하지 않다면 위의 모든 기계는 다음과 같이 쓸 수 있습니다.

import scala.actors.Futures._ 

def transform(payload : String) = {  
    val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString 
    println("transformed " + payload + " to " + result) 
    result 
} 

val results = for (i <- 0 to 1000) yield future(transform(i.toString)) 
+0

준비가 무엇을 의미하는지 설명 할 수 있습니까? –

+0

준비가되었습니다이 예제에서는 전달할 메시지의 역할을하는 사례 클래스입니다. 코디네이터는 기본적으로 '준비 됐니?'라는 의미의 준비 메시지를 소비자에게 보냅니다. 소비자는 '예'를 의미하는 준비 메시지로 응답합니다. 응답 할 첫 번째 소비자는 요청을 전달합니다. – harmanjd

0

여러 가지 일을하고 싶다면 여러 배우를 사용해야합니다. 배우를 사용하는 모든 이유는 여러 독립적 인 프로세스간에 작업을 나누는 것입니다.

+0

이것은 도움이되지 않는 대답입니다. 처리 할 이벤트를 읽고 처리 할 다른 배우에게 보내는 배우가 있다고 가정 해 보겠습니다. 실제로는 실제 처리 코드가 정확히 동일하더라도 여러 이벤트를 동시에 처리 할 수 ​​있습니다 (따라서 한 곳, 즉 1 명의 액터에서 작성합니다). 액터 프레임 워크가 프로그래밍 리소스를 최대한 활용할 수 있도록 이러한 (동일한) 액터를 "복제"(또는 풀 생성)하게하려면 어떻게해야합니까? –

+0

"내 프로세서 리소스를 최대한 활용할 수 있습니다." –

+1

질문에 제대로 액자가 맞지 않아서 제 답변이 도움이되지 않았습니다. 액터는 코드 조각이 아닌 프로세스입니다. 객체가 클래스의 인스턴스와 같습니다. 여러 메시지를 처리하기 위해 여러 액터를 만드는 방법을 묻지 않았습니다. 배우가 여러 메시지를 동시에 처리 할 수있는 방법을 알고 싶었습니다. 제 대답은 제가 배우 모델에 대한 당신의 오해로 인식 한 것을 분명히하려는 시도였습니다. – mamboking

6

대답은 Actor이 비동기 적으로 메시지를 처리 ​​할 수 ​​없다고 생각합니다. 이러한 메시지 비동기을 처리 할 수있는 메시지를 듣고해야 Actor이 있다면, 그것은 다음과 같이 작성할 수 있습니다 :

val actor_ = actor { 

    loop { 
    react { 
     case msg => 
     //create a new actor to execute the work. The framework can then 
     //manage the resources effectively 
     actor { 
      //do work here 
     } 
     } 
    } 
    }