2011-04-09 6 views
11

좋아, 이것은 다소 어리석은 질문 일지 모르지만 액터 프레임 워크 내에서 병렬 컬렉션을 사용하면 어떤 이점이 있습니까? 즉, 한 번에 하나의 메시지 만 배우의 사서함에서 처리하는 경우 병렬 수집이 필요한 것입니까? 평행 한 컬렉션과 배우는 상호 배타적입니까? 두 가지 모두를 포함하는 유스 케이스는 무엇입니까?스칼라 2.9와 액터의 병렬 컬렉션

답변

15

그들은 다른 문제를 해결합니다. 배우들은 task parallel problems을 해결하는 데 능숙합니다. 병렬 수집은 data parallel problems을 해결하는 데 능숙합니다. 나는 그들이 상호 배타적이라고 생각하지 않습니다 - 당신은 액터에서 병렬 컬렉션을 사용할 수 있고 액터를 포함하는 병렬 컬렉션을 사용할 수 있습니다.


편집 - 빠른 테스트하십시오 배우 알림 루프 혜택 같은 간단한 에도 뭔가.

다음 코드에서는 액터 레지스트리에 백만 명의 액터를 등록하여 이벤트를 알립니다.

내 컴퓨터 (4 코어 2.5GHz 노트북)에서 비 병렬 알림 루프 (registry foreach {})의 평균 소요 시간은 2.8 초입니다. 병렬 수집 루프 (registry.par.foreach {})를 사용하면 1.2 초가 걸리고 4 개의 코어가 모두 사용됩니다. 스칼라에서

import actors.Actor 

case class Register(actor: Actor) 
case class Unregister(actor: Actor) 
case class Message(contents: String) 

object ActorRegistry extends Actor{ 
    var registry: Set[Actor] = Set.empty 

    def act() { 
    loop{ 
     react{ 
     case reg: Register => register(reg.actor) 
     case unreg: Unregister => unregister(unreg.actor) 
     case message: Message => fire(message) 
     } 
    } 
    } 

    def register(reg: Actor) { registry += reg } 

    def unregister(unreg: Actor) { registry -= unreg } 

    def fire(msg: Message){ 
    val starttime = System.currentTimeMillis() 

    registry.par.foreach { client => client ! msg } //swap registry foreach for single th 

    val endtime = System.currentTimeMillis() 
    println("elapsed: " + (endtime - starttime) + " ms") 
    } 
} 

class Client(id: Long) extends Actor{ 
    var lastmsg = "" 
    def act() { 
    loop{ 
     react{ 
     case msg: Message => got(msg.contents) 
     } 
    } 
    } 
    def got(msg: String) { 
    lastmsg = msg 
    } 
} 

object Main extends App { 

    ActorRegistry.start 
    for (i <- 1 to 1000000) { 
    var client = new Client(i) 
    client.start 
    ActorRegistry ! Register(client) 
    } 

    ActorRegistry ! Message("One") 

    Thread.sleep(6000) 

    ActorRegistry ! Message("Two") 

    Thread.sleep(6000) 

    ActorRegistry ! Message("Three") 

} 
+0

답변 해 주셔서 감사합니다. 나는 액터 내에서 병렬 컬렉션을 사용할 수 있다는 것을 알 수 있지만이 경우에는 일반 콜렉션을 사용하는 것보다 더 유리할 것으로 보이지 않습니다. 반면에 액터가 포함 된 병렬 컬렉션을 사용한다는 생각은 유용하게 보입니다. 나는 그 생각을 좋아한다. 생각에 음식을 주셔서 감사합니다 ... –

+1

테스트 코드를 작성해 주셔서 감사합니다. 정말 감사. –

+0

@ Bruce. 여기에 병렬 수집을 사용할 수있는 또 다른 기회가 있음을 주목하십시오. 위의 코드는 init 루프를 수행하는 데 약 12 ​​초가 걸립니다. 우리가 병렬 처리하면 약 4 초 ((1 ~ 1000000) .par.foreach {i => ...}) 걸립니다. –

2

배우 라이브러리는, 옵션 중 하나에 불과 많은 (스레드 & 잠금 장치, STM, 선물/약속) 중, 동시성에 접근하고,이 문제의 모든 종류에 사용되는 가정, 또는 아니에요 (배우와 STM이 함께 좋은 거래를 할 수는 있지만) 모든 것과 결합 할 수 있어야합니다. 경우에 따라 액터 그룹 (worker + supervisor)을 설정하거나 포크 조인 풀에 작업을 명시 적으로 분할하여 작업을 수행하는 것은 너무 번거롭기 때문에 기존 작업에 .par을 호출하는 것이 편리합니다. 이미 사용하고있는 컬렉션을 병렬로 간단히 탐색하여 거의 무료로 (설치면에서) 성능상의 이점을 얻을 수 있습니다.

모두 배우와 병렬 컬렉션은 문제의 다른 차원입니다. 행위자는 동시성 패러다임이지만 병렬 컬렉션은 동시성 대안으로보기보다는 오히려 동시성 대안으로보아야하는 유용한 도구이지만 오히려 컬렉션 도구 모음.

+0

의견을 보내 주셔서 감사합니다. 말된다. –

관련 문제