如何用Akka演员解决这个问题?

时间:2015-10-25 10:23:21

标签: akka reactive-programming

不知道如何命名这个帖子,但会尝试用几行来解释这个问题。

我有一个命令需要计算所需日期范围的价格。要计算它,系统需要单独获取每天的价格(数据库,配置,缓存,无论从哪里开始)。

我的建议是让一个PriceRangeActor有一个DailyPriceActors池,并向他们发送像CalculateDailyPrice这样的命令。

但是如何在PriceRanceActor中组装所有数据?

1。 有一些复杂键的大地图只是闻起来很多。如何确定范围是否完全计算?有没有更简单的方法呢?

2。 为每个命令创建新的PriceRangeActor并使用ask模式查询DailyPriceActors列表?

1 个答案:

答案 0 :(得分:1)

因为你没有使用任何消息传递/排队我建议使用Futures而不是Actors作为你的并发抽象机制。这个blog entry提出了一个非常有说服力的论点,即Actors用于状态,而Futures用于计算。

使用期货或演员?(这是一个未来),你可以使用Future.sequence将所有单独的查询期货捆绑在一起,只有在所有子查询都完成后才能完成完整。

使用期货(推荐)

import scala.concurrent.Future

object Foo extends App {

  type Date = Int
  type Prices = Seq[Float]
  type PriceMap = Map[Date, Prices]

  //expensive query function
  def fetchPrices(date : Date) : Prices = ???

  //the Dates to query Prices for
  val datesToQuery : Seq[Date] = ???

  import scala.concurrent.ExecutionContext.Implicits._

  def concurrentQuery(date : Date) : Future[Prices] = Future {fetchPrices(date)}      

  //launches a Future per date query, D Dates => D Futures
  //Future.sequence converts the D Futures into 1 Future
  val dates2PricesFuture : Future[PriceMap] = 
    Future.sequence(datesToQuery map concurrentQuery)
          .map(datesToQuery zip _)  
          .map(_.toMap)      

  dates2PricesFuture onSuccess { case priceMap : PriceMap =>
    //process the price data which is now completely available
  }

}//end object Foo

使用ACTORS

import scala.concurrent.Future
import akka.actor.{Actor, ActorSystem, Props}
import akka.pattern.ask
import akka.util.Timeout

object Foo extends App {          
  type Date = Int
  type Prices = Seq[Float]
  type PriceMap = Map[Date, Prices]

  def fetchPrices(date : Date) : Prices = ???

  val datesToQuery : Seq[Date] = ???

  class QueryActor() extends Actor {
    def receive = { case date : Date => sender ! fetchPrices(date) }
  }

  implicit val as = ActorSystem()
  implicit val queryTimeout = Timeout(1000)

  import as.dispatcher

  def concurrentQuery(date : Date) : Future[Prices] =    
    ask(as actorOf Props[QueryActor],date).mapTo[Prices]

  val dates2PricesFuture : Future[PriceMap] = 
        Future.sequence(datesToQuery map concurrentQuery)
              .map(datesToQuery zip _)  
              .map(_.toMap)

  dates2PricesFuture onSuccess ... //same as first example

}//end object Foo