要求を識別する一意の識別子は、問題を解決する1つの方法です。俳優の中のマップ(calcRegistry
)は、先に到着したFractionComponent
(Numerator
またはDenominator
のいずれか)を保持しています。ペアの2番目の部分が入ったら、すでに行ったように計算を開始することができます。
実装では、2番目のペアが受信されず、マップが拡大し続けるメモリリークの問題は解決されていません。
import akka.actor.{Actor, ActorSystem, Props}
object Main extends App {
import Funnel._
val system1 = ActorSystem("funnelTest")
val input = system1.actorOf(Props[Funnel], "input")
(1 to 10) foreach { number =>
val id = java.util.UUID.randomUUID().toString
input ! Numerator(id, value = number + 2)
input ! Denominator(id, value = number + 1)
}
system1.awaitTermination()
}
class Funnel extends Actor {
import Funnel._
import scala.collection._
val calcRegistry = mutable.Map[String, FractionComponent]()
def saveToRegistry(comp: FractionComponent) = calcRegistry(comp.id) = comp
def printValue(num: Numerator, den: Denominator) = println(s"aggregated, ${num.value}/${den.value} = ${num.value/den.value}")
def receive = {
case [email protected](id, _) =>
if (calcRegistry contains id)
self ! Run(num, calcRegistry(id).asInstanceOf[Denominator])
else saveToRegistry(num)
case [email protected](id, _) =>
if (calcRegistry contains id)
self ! Run(calcRegistry(id).asInstanceOf[Numerator], den)
else saveToRegistry(den)
case Run(num: Numerator, den: Denominator) =>
calcRegistry.remove(num.id)
printValue(num, den)
case _ =>
}
}
object Funnel {
sealed trait FractionComponent {
def id: String
}
case class Numerator(override val id: String, value: Double) extends FractionComponent
case class Denominator(override val id: String, value: Integer) extends FractionComponent
case class Run(num: Numerator, denominator: Denominator)
}
出力例:
aggregated, 3.0/2 = 1.5 aggregated, 4.0/3 = 1.3333333333333333 aggregated, 5.0/4 = 1.25 aggregated, 6.0/5 = 1.2 aggregated, 7.0/6 = 1.1666666666666667 aggregated, 8.0/7 = 1.1428571428571428 aggregated, 9.0/8 = 1.125 aggregated, 10.0/9 = 1.1111111111111112 aggregated, 11.0/10 = 1.1 aggregated, 12.0/11 = 1.0909090909090908
参考:Reactive Messaging Patterns with the Actor Model
なぜあなたはあなたの実装がスケーラブルではないと思いますか? (これはわずかに改善することができますが、 "!Run"を新しいメソッドrun()への呼び出しで置き換えてください。これは現在の "case Run"と同じです)。 –