_bitácora

Futuros y actores en Scala y Akka

Por Yuji Kiriki

Tradicionalmente, construir aplicaciones que soporten concurrencia en la JVM siempre ha sido problema del servidor de aplicaciones. Pocas veces nos veíamos en la tarea de implementar o de pensar en problemas de semáforos, hilos y procesos y, cuando teníamos que hacerlo, es porque el servidor de aplicaciones no daba más.

El número de usuarios y de aplicaciones integradas de hoy nos ha llevado a buscar alternativas ligeras y más adecuadas para soportar crecimientos súbitos en la demanda de recursos, de conexiones y de la disponibilidad misma de las aplicaciones; permitiendo dar respuestas correctas en un tiempo tolerable.

Los Futuros en Scala (implementados en varias librerías) y el modelo de actores en Akka, permiten modelar e implementar soluciones que aprovechan las características del hardware moderno: múltiples núcleos de procesamiento, centenas de miles de megas de memoria; redundando en la capacidad de soportar concurrencia aumentando su disponibilidad y comportamiento correcto.

Los beneficios no solo se miden a través del desempeño de una solución. El nivel de abstracción en el que se razona sobre Futuros o actores permite diseñar y escribir código concurrente y paralelo, de fácil lectura, que atiende la concurrencia de manera elegante y digerible.

Por estos hechos y razones, consideramos compartir una análisis a través de la cual puedan hacer la elección de la herramienta más adecuada para sus escenarios donde se presente concurrencia, proponiendo y promoviendo así el “fin de vida” de lo servidores de aplicaciones.

Cuándo Actores

La mayor ventaja del modelo de actores sobre los futuros es su capacidad de mantener estado y protegerlo de la concurrencia. Si a esta propiedad se le suma su similitud con la noción de objetos del paradigma orientado a objetos (OO), las soluciones que se pueden implementar son simples y potentes.

Lo simple nace del fomento de la simpatía semántica al combinar el modelo de actores con los principios del diseño OO. Esta combinación puede entenderse como un mutualismo donde, en la solución de software, el modelo de actores se ve fortalecido por OO y OO se ve enriquecido por el modelo de actores.

El mutualismo se fundamenta en la noción de estado de los actores y de los objetos. Al ser dos ideas análogas, se pueden aplicar los principios de OO en el diseño de los actores, siendo cada uno de ellos interpretados como objetos que protegen su encapsulamiento a través del intercambio de mensajes.

En una entrevista, Alan Kay (para algunos el fundador del paradigma objetual), admite esta relación:

Binstock: How do you view the Actor model?

Kay: The first Smalltalk was presented at MIT, and Carl Hewitt and his folks, a few months later, wrote the first Actor paper. The difference between the two systems is that the Actor model retained more of what I thought were the good features of the object idea, whereas at PARC, we used Smalltalk to invent personal computing. It was actually a practical programming language as well as being interesting theoretically. I don’t think there were too many practical systems done in Actors back then.

Cabe notar que OO es un paradigma de programación mientras que los actores son un modelo de computación. No obstante, la noción de estado sirve como articulador entre ellas.

Ahondando en esta relación por el lado OO, podemos hacer uso de las prácticas de Domain-Driven Design. Los patrones tácticos son fácilmente implementados en el modelo de actores permitiendo tener grafos de actores que modelan dominios de negocio. No solo ahí se fomenta el mutualismo. Si hacemos uso de los actores como modelo de concurrencia para sistemas distribuidos, podemos escribir aplicaciones de software que implementan modelos de dominio listos para soportar concurrencia y para ser distribuidos en una red. Quizás, esta última, sea la característica de más potencial de los actores sobre los futuros.

Otra ventaja de los actores sobre los futuros es la capacidad de distribuir trabajo sobre un sistema distribuido. A través de sus principios, el modelo de actores permite distribuir no solo concurrencia sino carga en varios nodos, permitiendo la presencia de procesamiento paralelo. No obstante, hay investigación de cómo tener funciones distribuidas.

Es necesario recordar que el modelo de actores no es un artefacto de la programación funcional. Sin embrago desde el punto de vista de la programación funcional, los actores adolecen de:

Cuándo Futuros

Los futuros son una abstracción que sirve para representar acciones asíncronas. Pueden ser vistos como un mecanismo para manejar asincronía un nivel de abstracción por encima de usar callbacks. Citando a Marius Eriksen:

Futures model the real world truthfully: A Future[T] represents a T-typed result, which may or may not be delivered at some time in the future, or which may fail altogether. Like real-world asynchronous operations, a future is always in one of 3 states: incomplete, completed successfully, or completed with a failure.

Existen diversas implementaciones de futuros en Scala: en la librería estándar, y en librerias como akka, finagle y scalaz. Para efectos de esta entrada lo importante es que estas instancias implementan:

Los futuros presentan varias ventajas:

Por último los futuros tienen una desventaja considerable, que tiene que ver con los casos de uso para los cuales fueron ideados. Los futuros no son adecuados para manejar estado: por ejemplo tener estado mutable que puede ser modificado por dos futuros distintos es una receta para hacer un desastre. En general este es un corolario del consabido consejo de no compartir recursos entre threads distintos. Por lo tanto es difícil utilizar futuros para modelar aspectos del dominio, aspectos que por lo general requieren algún tipo de estado. En conclusión los futuros sirven para manejar concurrencia y paralelismo de funciones que carecen de estado dentro de una misma JVM. Cuando se quiere realizar distribución entre distintas maquinas o concurrencia protegiendo estado los actores representan una abstracción adecuada.

Conclusión

Los Actores y los Futuros son dos abstracciones útiles que permiten manejar concurrencia. El uso de uno no excluye automáticamente el uso del otro. Por el contrario, usualmente son colaborativos: e.g. un Actor puede despachar trabajo a un Futuro.

En esta entrada analizamos las ventajas de cada uno y sus mejores casos de uso, pero cabe aclarar que el mundo de Scala es prolífico en abstracciones y hay muchas alternativas que pueden ser más adecuadas para ciertos casos de uso. Hay muchas que no mencionamos como Iteratees, scalaz-streams y la iniciativa de Reactive Streams.

El mundo de Scala y la JVM es rico, los actores y los Futuros son solo las primeras abstracciones que tenemos para explorar.

Referencias

bitacora/