簡體   English   中英

並行執行期貨清單

[英]Execute list of Futures in parallel

我對Scala的Future和Akka還是陌生的,目前,我正在嘗試實現一個應用程序,該應用程序執行一系列獨立任務並將結果匯​​總在一起。

例如,我想要一個包含多個任務的應用程序,每個任務接收一個數字,休眠幾秒鍾,然后返回“ Hello”消息。

參與者的實現如下:

class HelloActor extends Actor {
  def receive = {
    case name:Int => {
      println("%s will sleep for %s seconds".format(name, name % 4))
      Thread.sleep(name % 4 * 1000)
      sender ! "Hello %s".format(name)
    }
  }
}

主要對象實現為:

object HelloAkka extends App {
  val system = ActorSystem("HelloSystem")

  val helloActor = system.actorOf(Props[HelloActor], name = "helloactor")

  implicit val timeout = Timeout(20, TimeUnit.SECONDS)

  val futures = (1 to 10).map(num => {
    helloActor ? num
  })

  val future = Future.sequence(futures)

  val results = Await.result(future, timeout.duration)

  println(results)

  system.shutdown
}

由於每個任務將休眠0、1、2或3秒,因此我希望首先執行睡眠時間較短的任務。 但是,結果是:

1 will sleep for 1 seconds
2 will sleep for 2 seconds
3 will sleep for 3 seconds
4 will sleep for 0 seconds
5 will sleep for 1 seconds
6 will sleep for 2 seconds
7 will sleep for 3 seconds
8 will sleep for 0 seconds
9 will sleep for 1 seconds
10 will sleep for 2 seconds
Vector(Hello 1, Hello 2, Hello 3, Hello 4, Hello 5, Hello 6, Hello 7, Hello 8, Hello 9, Hello 10)

換句話說,所有任務均按順序執行。 我想知道是否有其他方法可以並行執行所有任務。

如評論中所述,您將所有任務/消息發送給一個參與者,並且可以保證所有這些任務/消息都將按順序處理。

要並行處理任務,您需要具有處理程序actor的多個實例,在這種情況下為HelloActor

當然,您可以只創建HelloActor多個實例,但這絕對不是一個好習慣。

對於此類任務,您應該使用內置路由功能,該功能允許您管理工作程序/處理程序池並通過一個router角色與之交互。

val router: ActorRef =
  context.actorOf(RoundRobinPool(10).props(Props[HelloActor]), "router")

...
router ? num
...

請遵循Akka Routing文檔以獲取更多詳細信息。

我建議不要在評論和答案中建議多個參與者,而建議在Future執行實際任務。 因此,您的演員將更像是任務的協調員。 例如:

//...    

// import pipe pattern to get access to `pipeTo` method
import akka.pattern.pipe
import scala.concurrent.Future

// the `Future`s will be executed on this dispatcher
// depending on your needs, you may want to create a 
// dedicated executor for this
class TaskCoordinatorActor extends Actor {
  import context.dispatcher

  def receive = {
    case name: Int =>
      Future {
        Thread.sleep(name % 4 * 1000)
        "Hello %s".format(name)
      } pipeTo sender()
  }
}

上面的代碼在scala.concurrent.Future執行您的任務,並將結果通過管道傳輸到原始發件人。 這樣,actor不會在任務完成之前阻塞,但是一旦創建了Future即可准備接收下一條消息。

PS:您應該創建消息類型,而不是發送普通整數,這些消息類型會明確表明您希望角色執行的操作。 在您的情況下,例如:

case class Sleep(duration: Duration)

從同一角色發送到同一角色的消息將按順序執行。

您有兩個選擇。

為每條消息創建一個新的HelloActor副本,以便它們全部並行執行,或者將HelloActor修改為如下所示(可能是錯誤的導入,由內存進行):

import akka.pattern.pipe._

class HelloActor extends Actor {
  def receive = {
    case name:Int => {
      println("%s will sleep for %s seconds".format(name, name % 4))
      Future(sleepAndRespond(name)) pipeTo sender
   }
 }

 def sleepAndRespond(name:String) = {
   Thread.sleep(name % 4 * 1000)
   "Hello %s".format(innerName)
 }
}

這樣,執行的順序部分只是未來的管道,然后針對十個消息中的每一個異步執行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM