Scala 액터는 여러 메시지를 동시에 처리할 수 있나요?
-
06-07-2019 - |
문제
답장 내 최근 질문에 따르면 배우가 메시지를 처리한 것으로 나타났습니다. 한번에 한.이것이 사실입니까?나는 명시적으로 그렇게 말하는 것을 보지 못했습니다. 스칼라로 프로그래밍하기)에는 다음 스니펫(pp.593)
만약 [
react
method]가 처리할 수 있는 메시지를 찾으면 [it]이 해당 메시지 처리를 예약합니다. 나중에 실행하기 위해 그리고 예외를 던져라
(내 자신을 강조).두 가지 관련(상호 배타적) 질문:
- 행위자가 여러 메시지를 동시에 처리할 수 있다고 가정할 때, 행위자가 한 번에 하나씩 메시지를 처리하도록 하려면 어떻게 해야 합니까(이렇게 하려는 경우)?(사용
receive
?) - 액터가 메시지를 한 번에 하나씩 처리한다고 가정하면 실제로 액터를 가장 잘 구현하는 방법은 무엇입니까? ~할 수 있었다 메시지를 동시에 처리
편집하다:약간의 테스트를 수행하면 내가 틀렸고 액터가 실제로 순차적이라는 것이 입증되는 것 같습니다.그래서 제가 대답해야 할 것은 질문 #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
}
}
}
}
여러 가지 작업을 수행하려면 여러 액터를 사용해야 합니다.액터를 사용하는 전체 이유는 작업을 여러 개의 독립적인 프로세스로 나누기 위한 것입니다.