2009-06-17 61 views
27

The reply我最近的一個問題表明,演員一次處理了一條消息。這是真的?我看沒有什麼明確的說,(在編程在斯卡拉),其中包含下面的代碼片段(第593)Scala可以同時處理多個消息嗎?

如果[該react方法]認爲,可以處理的消息,[它]會安排該消息的處理用於稍後執行並拋出異常

(強調我自己的)。兩個相關的(和相互排斥的)問題:

  1. 假設一個演員可以simulatenously處理多條消息,我怎麼能強迫一個演員一次處理的消息1(如果這是我希望做)? (使用receive?)
  2. 假設一個演員處理郵件一次一個,我將如何最好地實現這實際上可能處理消息的同時

編輯演員:做了一些測試,似乎承認我錯了,演員確實是連續的。所以這是問題#2,我需要回答

+5

我真的不明白這個問題是如何證明downvote。如果我可以閱讀關於Scala編程中演員的完整章節並且不確定答案,那麼這是一個完全有效的問題。 – 2009-06-18 07:33:55

+0

單個參與者按順序處理消息,因爲這個想法是可以使用參與者調解對(另外的)共享資源的訪問,並且不需要共享資源上的其他同步。如果消息可以按順序處理,則需要在演員中使用鎖,以確保不會發生同步錯誤。 – 2010-01-04 06:27:15

回答

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) 

此代碼測試以查看哪些消費者可用並向該消費者發送請求。替代方案是隨機分配給消費者或使用循環調度程序。

根據你在做什麼,你可能會更好地服務於斯卡拉的期貨。例如,如果你真的不需要演員,那麼所有上述機器可以寫爲

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

這是一個無益的答案。比方說,我有一些演員讀取要處理的事件並將它們發送給其他演員進行處理。除此之外,即使實際處理代碼完全相同(因此我將在一個地方寫入,即1個參與者),也可以同時處理多個事件。我如何讓演員框架「複製」(或創建一個池)這些(相同的)演員,以便我可以充分利用我的編程資源? – 2009-06-17 13:45:32

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 
     } 
     } 
    } 
    } 
相關問題