tutorial que programacion modelo actores scala asynchronous akka actor inbox

scala - que - Interactuar con actores externos de Akka



modelo de actores programacion (3)

Quiero interactuar con los actores de Akka desde mi propio hilo. Actualmente, me gusta así:

val res = Await.result(aref ? GroupReceive(fromRank), timeout.duration).asInstanceOf[T]

Pero no estoy seguro de cómo esto realmente interactúa con mi hilo? Deseo que la recepción sea asincrónica, es decir, quiero colgar el hilo mientras recibo para permitir que se realice otro trabajo. Acabo de leer sobre el sistema de bandeja de entrada de Akka. inbox akka api

Creo recordar que Await crea un nuevo actor cada vez. ¿Cuáles son las diferencias entre await + ask y inbox, y alguien puede darme un ejemplo de cómo crear una bandeja de entrada y utilizarla para comunicarse con actores de "afuera"?

EDITAR Solo para aclarar, no quiero que el mismo subproceso siga funcionando, quiero que deje de acaparar un núcleo de CPU y deje que otros subprocesos funcionen hasta que reciba algo, y luego se despierta de nuevo.


Como está escrito en la documentación de Akka''s Future, usar Await bloquea el hilo actual hasta esperar el resultado.

Ejemplo

import scala.concurrent.Await import akka.pattern.ask import akka.util.Timeout import scala.concurrent.duration._ implicit val timeout = Timeout(5 seconds) val future = actor ? msg // enabled by the “ask” import val result = Await.result(future, timeout.duration).asInstanceOf[String]

Esto hará que el hilo actual se bloquee y espere a que el actor ''complete'' el futuro con su respuesta.

Usar con actores


Si no quiere bloquear en el lado de la llamada, entonces no use Await, use las devoluciones de llamada que no bloqueen en su lugar, como onSuccess, onFailure y onComplete. Cuando hace esto, se coloca una tarea futura en cualquier ámbito ExecutionContext en el momento de ask (?). Cuando se recibe una respuesta, esta devolución de llamada se invoca de forma asíncrona a través de ExecutionContext. De esta forma evitará bloquear todos juntos en el hilo que está haciendo la solicitud al actor y luego la devolución de llamada se maneja en el grupo de hilos vinculado al ExecutionContext.

Además, creo que las cosas de la bandeja de entrada que mencionas están orientadas a probar cosas de los actores en el REPL (al menos eso es lo que dicen los documentos sobre ActorDsl). Sigue con el enfoque que tienes de usar ask desde fuera del actor. Deje que akka cree el actor efímero que necesita para la comunicación bajo el capó para llamadas de no actor a actor. Luego simplemente cambie a una devolución de llamada sin bloqueo como sugerí anteriormente. Creo que eso es lo que estás buscando.


Await.receive es parte de la API de concurrencia de Scala y no tiene nada que ver con los actores. Su propósito es bloquear el hilo actual hasta que se complete el futuro previsto, o el límite de tiempo de espera entre en acción y todo termina en una excepción de tiempo de espera excedido.

¿El operador preguntar ? de hecho creará un actor temporal con el único propósito de esperar la respuesta del actor señalado por la variable aref y completar el futuro que recibió cuando llamó al operador ask con la respuesta recibida.

Entonces, tu código esencialmente está bloqueando todo el hilo. Como se indicó, si desea liberar el hilo actual y continuar haciendo otro trabajo, puede adjuntar una devolución de llamada al futuro.

implicit val ctx: ExecutionContext = //provide execution context here implicit val timeout: Timeout = // provide timeout here aref ? GroupReceive(fromRank)) onSuccess { res => //do something with res here, asynchronously } // some other code which runs without being blocked...

El código anterior se puede reescribir con el actor DSL que mencionaste anteriormente:

import akka.actor.ActorDSL._ implicit val actorSystem: ActorSystem = // provide an actor system here or any actor ref factory actor(new Act { aref ! GroupReceive(fromRank) context.setReceiveTimeout(timeout) //optional become { case ReceiveTimeout => { //handle the timeout context.stop(self) } case res => { //do your thing with res, asynchronously context.stop(self) } } } //some other code which won''t wait for the above operations

La última versión también crea un nuevo actor temporal que envía el mensaje GroupReceive y luego espera una respuesta, después de lo cual se mata.

La conclusión es que para recibir un mensaje de un actor debes ser un actor. Los actores no pueden simplemente enviar mensajes a otra cosa que no sea ActorRef .

Entonces, o bien utilizas el patrón ask que crea un actor temporal detrás de escena y administra el ciclo de vida de este actor temporal, exponiéndote a un simple futuro simple para trabajar, o puedes crear tú mismo el actor temporal, pero luego debes administrarlo su ciclo de vida (es decir, recuerda matarlo una vez que ha hecho su trabajo)

Elija la opción que más le convenga.