문제

답장 내 최근 질문에 따르면 배우가 메시지를 처리한 것으로 나타났습니다. 한번에 한.이것이 사실입니까?나는 명시적으로 그렇게 말하는 것을 보지 못했습니다. 스칼라로 프로그래밍하기)에는 다음 스니펫(pp.593)

만약 [ react method]가 처리할 수 있는 메시지를 찾으면 [it]이 해당 메시지 처리를 예약합니다. 나중에 실행하기 위해 그리고 예외를 던져라

(내 자신을 강조).두 가지 관련(상호 배타적) 질문:

  1. 행위자가 여러 메시지를 동시에 처리할 수 있다고 가정할 때, 행위자가 한 번에 하나씩 메시지를 처리하도록 하려면 어떻게 해야 합니까(이렇게 하려는 경우)?(사용 receive?)
  2. 액터가 메시지를 한 번에 하나씩 처리한다고 가정하면 실제로 액터를 가장 잘 구현하는 방법은 무엇입니까? ~할 수 있었다 메시지를 동시에 처리

편집하다:약간의 테스트를 수행하면 내가 틀렸고 액터가 실제로 순차적이라는 것이 입증되는 것 같습니다.그래서 제가 대답해야 할 것은 질문 #2입니다.

도움이 되었습니까?

해결책

행위자는 한 번에 하나의 메시지를 처리합니다.여러 메시지를 처리하는 일반적인 패턴은 소비자 행위자 풀 앞에 하나의 코디네이터 행위자를 두는 것입니다.반응을 사용하면 소비자 풀이 커질 수 있지만 여전히 소수의 JVM 스레드만 사용합니다.다음은 10명의 소비자 풀과 그들을 대표하는 1명의 코디네이터를 만드는 예입니다.

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의 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))

다른 팁

내 생각에 그 대답은 다음과 같다. 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
        }
      }
    }
  }

여러 가지 작업을 수행하려면 여러 액터를 사용해야 합니다.액터를 사용하는 전체 이유는 작업을 여러 개의 독립적인 프로세스로 나누기 위한 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top