sábado, 1 de octubre de 2022

Primeros pasos con Akka


Ante de empezar veamos este link, para ponernos en contexto : 
https://emanuelpeg.blogspot.com/2022/09/por-que-usar-akka.html

Implementamos el trait Actor en una clase simple llamada Contador. 

import akka.actor.Actor


class Counter extends Actor {

  var count = 0

  def receive = {

    case "incr" ⇒ count += 1

    case "get"  ⇒ sender() ! count

  }

}


Este tiene un campo count y debe implementar el método de receive del trait Actor y debe devolver una función parcial. Esa es la función parcial con una declaración de pattern matching con el mensaje entrante. 

Entonces, si recibimos un mensaje con una cadena incr, entonces queremos incrementar el contador. Lo que hacemos aquí. Si queremos que tenga estado, queremos permitir que otros actores averigüen cuál es el valor del contador. Y por lo tanto los actores pueden enviar mensajes a direcciones que conocen. Las direcciones en Akka están modeladas por el tipo ActorRef. Entonces, escribimos otro caso, y si obtenemos una tupla con la cadena get, y algo con tipo ActorRef, que llamamos cliente, entonces podemos enviar al cliente, el conteo como un mensaje. 

El operador de signo de exclamación que se usa para enviar mensajes y se pronuncia tell en Akka. Cada actor conoce su propia dirección. Es un ActorRef llamado self. Y está implícitamente disponible. ActorRef es una cláusula abstracta que tiene un método llamado tell o signo de exclamación. Y si usa el signo de exclamación que es la buena sintaxis de Scala, tell que es más para Java. Esto requiere un argumento implícito. 

El argumento implícito de tipo ActorRef se recoge del entorno. Entonces, si usa el operador Tell dentro de un actor, implícitamente seleccionará al remitente como la referencia propia de ese actor. Dentro del actor receptor, este valor está disponible como remitente, que devuelve la referencia del actor que ha enviado el mensaje que se está procesando actualmente.

La referencia junto con el mensaje al actor receptor debe hacerse explícitamente en otras implementaciones de actor como erlang. Pero como es un patrón tan común, existe el metodo sender()  que es la referencia al que me envia el mensaje.

Un actor puede hacer más cosas que simplemente enviar mensajes. Puede crear otros actores y puede cambiar su comportamiento. Para acceder a estas funciones, necesitamos conocer el contexto del actor. 

El tipo de actor en sí solo tiene el método de recepción, por lo que solo describe el comportamiento del actor. La maquinaria de ejecución la proporciona el contexto del actor. 

Se tienes acceso al contexto dentro del actor simplemente diciendo contexto. Ahora veamos esto en acción. Podemos reformular nuestro contador en uno que no tenga barra. Será un objeto con estado sin una variable explícita. 

Primero, necesitamos definir un método, que nos dé un comportamiento. Este método toma un argumento, cuál es el estado actual del contador. Empezamos con el contador en cero. Si recibimos un mensaje incr aquí, cambiamos nuestro comportamiento para que sea el de un contador de n más 1.  Dentro de este comportamiento del contador, en cualquier momento podemos obtener una solicitud, donde solo respondemos con el valor actual de los contadores. 

import akka.actor.Actor


class Counter extends Actor {

  def counter(n: Int): Receive = {

    case "incr" ⇒ context.became(counter(n + 1))

    case "get"  ⇒ sender() ! n

  }

  def receive = counter(0)

}

Puede ver aquí que se parece un poco a una función recursiva de cola, porque la llamamos dentro de sí misma, pero es asíncrona, porque context.become evalúa lo que se proporciona aquí solo cuando se procesa el siguiente mensaje. 

Esto es funcionalmente equivalente a la versión anterior del contador, pero tiene algunas ventajas. En primer lugar, solo hay un lugar donde se cambia el estado, y ese es el llamado a convertirse, y esto es muy explícito. La otra es que el estado se limita al comportamiento actual, por lo que no hay ninguna variable que podamos dejar en algún lugar en un estado desconocido. Siempre tenemos el estado actual aquí. 

Lo último que uno puede hacer fundamentalmente con los actores es crearlos y detenerlos. El contexto del actor tiene métodos para eso. Primero, actorOf, una descripción sobre cómo crear un actor y un nombre, y devuelve un ActorRef. Además, cada actor puede detener a otros actores. 

Una cosa a tener en cuenta aquí es que los actores siempre son creados por actores. Esto significa que naturalmente forman una jerarquía porque un actor es creado exactamente por otro actor. Y otra cosa a tener en cuenta es que detener aquí a menudo se aplica a la auto referencia, lo que significa que el actor decide que quiere terminar. Probemos todo esto en una aplicación ejecutable. 


import akka.actor.Actor

import akka.actor.Props


class CounterMain extends Actor {

  val counter = context.actorOf(Props[Counter], "counter")


  counter ! "incr"

  counter ! "incr"

  counter ! "get"


  def receive = {

    case count: Int ⇒

      println(s"count was $count")

      context.stop(self)

  }

}


Por supuesto, una aplicación también se modela como un actor en este modelo. Entonces lo llamamos CounterMain. Este es un actor y usa el contexto actorOf para crear un contador. Podemos decir Props Counter para crear un actor que no tome argumentos de constructor. Y como todas las cosas buenas. Necesita un nombre, lo llamamos contador en este caso. 

Luego enviamos mensajes a este contador, en este caso lo enviamos incr tres veces y luego lo enviamos get. Recuerde que enviar con el operador de tell dentro de un actor seleccionará la referencia propia como remitente. Y como el contador responderá, lo recibiremos en este actor. Aquí en nuestro comportamiento, recibimos la cuenta, que es de tipo int. Lo imprimiremos y luego nos detendremos. 

Para ejecutar esto, debemos decirle a Eclipse cómo ejecutar las aplicaciones de actor porque actualmente aún no lo sabe. Entonces creamos una configuración de ejecución. Utiliza la clase principal akka.Main que espera como primer argumento, el nombre de la clase, el nombre completo de la clase de actor que se va a instanciar. Entonces, si ejecutamos esto. Veremos que la cuenta imprime tres. Esta impresión se hizo con esta línea, así que recibimos el conteo del contador y recibimos tres porque incrementamos el contador tres veces.

Ahora hemos visto todas las cosas básicas que pueden hacer los actores. Cuando reciben un mensaje, pueden enviar mensajes, crear actores. Y pueden cambiar su comportamiento para el próximo mensaje,  este es el modelo actor de computación.

Dejo link : https://akka.io/

No hay comentarios.:

Publicar un comentario