[英]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.