2015-09-16 42 views
0

我的實際使用案例是MyActor收到一條消息以開始工作。該工作需要下載幾個網頁,因此它要求MyActor下載。每次文章完成下載時,MyActor都會響應。如何處理多個Akka Actor?

我的代碼有更好的設計模式嗎?似乎允許多個角色更新count變量是不好的,因爲我只關心每個actor的具體數量。

主要演員:

val count = 0 

def receive = { 
    case CountUpdate => count += 1 
    case Job => { 

     List(1, 2, 3).map{case num => 
      (new myActor ? ToDownload) 

      val tries = 0 
      while (tries < 10){ 
       print("Count is: " + count) 
       tries += 1 
       // sleep 10 seconds 
      } 

      count = 0 
     }   
    } 
} 

MyActor:

def receive = { 
    case ToDownload => sender ! CountUpdate 
} 

編輯:

如果我按照利用期貨的建議,不能這可能會導致一個競爭條件?

var downloads: List[Int] = List() 

urls.map{ case url => Future{ download(url) }.onComplete{ 
    case Success(value) => downloads = downloads :+ value 
    case Failure(value) => println("Failure") 
    } 
} 
+1

我不相信CountUpdate處理程序將在Job處理程序運行時運行 - Actor從郵箱中一次處理一個消息。因此,MyActor會將CountUpdates推入郵箱,但這些不會反映在count變量中,因爲您仍將處理Job。 –

+0

謝謝@RichHenry,這是真的,我沒有想到! – user2827214

+0

Np,我犯了同樣的錯誤,我用下面的答案解答了Promise。雖然請記住,我不認爲Promise可以發送給一個偏遠的演員 - 我不知道。 –

回答

1

您還可以創建Future來下載資源。一旦未來完成,你可以發送一條更新消息給可以對它作出反應的主角。 FutureexecutionContext執行。

class MainActor extends Actor { 
    var count = 0 

    override def receive: Receive = { 
    case CountUpdate => 
     count += 1 
     println("New count " + count) 
    case Job => 
     val batchIDs = List(1, 2, 3) 

     implicit val executionContext = ExecutionContext.fromExecutor(new ForkJoinPool()) 

     batchIDs.map { 
     batchID => 
      Future { 
      // do some work 
      }.onSuccess{ 
      case _ => self ! CountUpdate 
      } 
     } 
    } 
} 
+0

我想我的解釋可能不夠清楚。 List(1,2,3)中的每個項目表示要下載的需要保持獨立的批次,而不是單個文件。我猜如果它響應「batch_id」字段,MainActor可以按batch_id進行排序。謝謝! – user2827214

+0

這不是問題。您也可以創建一個包含批次的列表。然後,'map'操作的每個元素都定義了應該下載哪些資源。在這裏,我僅以單個文件爲例來實現它。 –

+0

@ user2827214我更新了代碼。你的意思是這樣的嗎? –

1

我會派一個scala.concurrent.Promise到資源加載演員,然後你可以調用.future它得到scala.concurrent.Future

資源加載器在Promise上調用.complete(),這又會導致調用Future上的完整處理程序。