2012-09-17 8 views
6

Estoy haciendo un pequeño actor de caché con Akka 2 y para que el actor no bloquee, realizo todos los cálculos dentro de futuros. Sin embargo, un problema es que este actor también necesita interactuar con un código que no está en sí mismo en un actor, por lo que necesito usar el patrón "preguntar" para obtener un valor.Akka evitando envolver futuro al responder al código que no es Actor

Mi pregunta es, ¿cómo evito envolver el futuro de mis cálculos dentro de otro futuro al usar el patrón preguntar?

Por ejemplo

val f = myCache ? GetOrCalc("myKey", myCalculation) // this will be a Future[Future[...]] but I would like a Future[...] 

// meanwhile, inside the actor 
def receive = { 
    case GetOrCalc(key, calculation) => 
     if (keyNotExists) sender ! Future { calculation() } // calculation() is long-running 
     else sender ! cacheMap(key) 
} 

Lo ideal sería que podría utilizar la función Future.pipeTo pero me temo que esto no quede cuenta como una "respuesta" para el código no el actor

Respuesta

6

Ésta es la solución:

val f = myCache ? GetOrCalc("myKey", myCalculation) 

def receive = { 
    case GetOrCalc(key, calculation) => 
     if (keyNotExists) Future { calculation() } pipeTo sender 
     else sender ! cacheMap(key) 
} 

de envío y de recepción-futuro "> http://doc.akka.io/docs/akka/2.0.3/scala/actors.html# Ask_Send-And-Receive-Future

+0

Extrañamente, esto es exactamente lo que tenía en mi pseudocódigo original y ni siquiera lo probé porque supuse que el pipa no funcionaría como una "respuesta". ¡Eso es lo que obtengo por no probar y solo asumir! Aunque a decir verdad este comportamiento no está en los documentos como mencioné anteriormente. Muchas gracias Viktor! – Aktau

+3

Confíe en el Klang –

+0

Me pregunto cómo "pipeTo sender" está accediendo con seguridad al remitente. Entiendo por qué no puede acceder al remitente desde dentro del futuro, pero ¿cómo es que el remitente de pipeTo no tiene el mismo problema? ¿Lo es porque pipeTo evalúa al remitente en el contexto del actor antes de que el futuro se complete? –

3

Añadir a onComplete el futuro del cálculo

def receive = { 
    case GetOrCalc(key, calculation) => 
     if (keyNotExists) // calculation() is long-running 
      Future { calculation() } onComplete { 
       case Right(result) => result match { 
         case Some(value) => sender ! value 
         case None => sender ! Status.Failure(new Exception("Cannot find the value")) 
        } 
       case Left(ex) => 
        sender ! Status.Failure(ex) 

      } 
     else sender ! cacheMap(key) 
} 

Y hay un artículo sobre el uso de Akka para construir un sistema de caché. http://letitcrash.com/post/30509298968/case-study-an-auto-updating-cache-using-actors

+0

¿Pero esto no se envía dos veces? Una vez al futuro [futuro [...]] (remitente! Futuro {...}) y otra vez un futuro [...] (valor del emisor)? ¿Funciona para el código de llamada sin agente? ¿Cómo se utiliza el mensaje CalcResult? – Aktau

+2

actualizó el código. En realidad, esta solución proviene del artículo (http://letitcrash.com/post/30509298968/case -study-a-auto-updating-cache-using-actors) y no tengo tiempo para ve rificarlo por ahora. Espero que esta sea una pista útil para ti. –

+0

Jeje, gracias! Estuve leyendo esa fuente hace un par de horas porque habla de Akka y el almacenamiento en caché. Supongo que no lo había leído lo suficiente, parece hacer las cosas más o menos de la forma en que quería hacerlo después de una inspección más cercana. Si funciona como esperaba, elegiré su respuesta como la correcta – Aktau

Cuestiones relacionadas