Concurrencia en Erlang y Ejemplos Prácticos

De Departamento de Informatica
Saltar a: navegación, buscar

Erlang es un lenguaje de programación declarativo usado para software escalable de sistemas de tiempo real con requerimientos de alta disponibilidad. El sistema runtime de Erlang tiene soporte para concurrencia, distribución, tolerancia a fallos y operación contínua (permitiendo el reemplazo de código "en caliente" en un sistema en ejecución y la ejecucción del antiguo y nuevo código al mismo tiempo)[1].

Erlang Studio

Resumen Principales Características:[2]

  • Lenguaje de programación funcional
  • Tiene soporte de concurrencia
  • Su distribución, la cual no posee una memoria compartida
  • Tolerancia a fallos
  • Recolector de basura
  • Reemplazo de código "en caliente"
  • Procesos concurrentes altamente aislados
  • La comunicación entre procesos con paso de mensajes
  • Manejo de funciones de orden superior
  • La comprobación de tipos es dinámica
  • Su evaluación de argumentos es estricta (se realiza tempranamente para permitir efectos secundarios)
  • Da la posibilidad de conectar con código en C, Java y otros lenguajes

El paradigma de programación de Erlang es funcional. Erlang pertenece a la clase de lenguajes "orientados a mensajes"[3], de tipado dinámico y tiene un conjunto de bibliotecas para la construcción de sistemas robustos llamado OTP (Open Telecom Platform).

La implementación de Ericsson es principalmente interpretada pero también existe un compilador de Erlang llamado HiPE[4] (sólo soportado en algunos sistemas).

Fué desarrollado por autores en Ericsson y Ellemtel Computer Science Laboratories[1] como software propietario pero fué cedido como software libre en 1998[5].

Contenido

Historia

Joe Armstrong, llamado Padre de Erlang.

Comenzó a ser desarrollado el año 1986 por Joe Armstrong para la empresa de telefonía Ericsson, comenzando con experimentos en los años siguientes [6]. El nombre nace inspirado en el matemático e ingeniero danés Agner Krarup Erlang (que trabajó en la teoría de colas), según el programador de Ericsson Bjarne Däcker, y también como una abreviación de "Ericsson Language"[7]. Las versiones iniciales fueron implementadas en Prolog, influenciado también por el lenguaje PLEX.

En el año 1990 Erlang fue presentado en la ISS'90, lo cual aumentó el número de usuarios. En años subsiguientes se desarrolló aún más, incrementando la velocidad, expandiéndose, desarrollando una interfaz gráfica, etc. En el año 93 se le añadió una distribución, permitiendo tener un sistema de Erlang homogéneo en diversos tipos de hardwares.

En el año 1998 Ericsson decidió prohibir el uso del lenguaje, con el fin de permitir nuevos productos, provocando que muchos empleados, entre ellos Armstrong, abandonaran la compañía. Ese mismo año el lenguaje pasó a ser de código abierto. Luego, en el 2004 la prohibición fue cancelada, permitiendo que varios de los empleados volvieran.

Concurrencia

Erlang tiene un modelo de concurrencia basado en procesos con el paso de mensajes asíncrono. Los mecanismos de concurrencia en Erlang son light-weight (livianos), los procesos requieren poca memoria. La creación y eliminación de procesos y el paso de mensajes requieren poco esfuerzo computacional[1].

El modelo de procesos se basa en el modelo Communicating Sequential Processes de C.A.R. Hoare[8].

Con el fin de controlar un conjunto de actividades paralelas, Erlang tiene primitivas para la multiprogramación: spawn comienza una computación paralela (llamando un proceso); send envía un mensaje a un proceso; y receive recibe un mensaje de un proceso.

La sintaxis Pid ! Msg es usada para enviar un mensaje. Pid es una expresión o constante para evaluar el id del proceso. Msg es el mensaje que será enviado a Pid. Todos los argumentos son evualuados antes de enviar el mensaje, de esta manera:

foo(12) ! math3:area({square, 5})

significa evaluar la función foo(12) (debe retornar un PID válido) y evaluar math3:area({square, 5}) y entonces enviar el mensaje (por ejemplo 25) al proceso. El orden de evaluación de los lados de la primitiva send (!) es indefinida.

La primitiva receive tiene la siguiente sintaxis:

receive
   Mensaje1 ->
      ... ;
   Mensaje2 ->
      ... ;
      ...
end

receive trata de recibir un mensaje el cual esta descrito en uno de los patrones Mensaje1, Mensaje2, ... . El proceso el cual esta evaluando esta primitiva es suspendido hasta que un mensaje calce con uno de los patrones dichos y es recibido. Si ocurre un calce, el código que sigue al lado de ‘->’ es evaluado.

Una descripción más precisa sería decir que send envía un mensaje a un buzón del proceso y que receive trata de eliminar el mensaje del buzón del proceso receptor. Receive toma el primer mensaje que calce de una cola de mensajes esperando. Si ninguno de los patrones calza con el mensaje el proceso es suspendido hasta que el próximo mensaje sea recibido. Los mensajes que no calzaron con ningún patrón son guardados para ser procesados después.

Ejemplos de código

Módulos

En Erlang todas las funciones pertenecen a un módulo particular. Las funciones exportadas pueden correr afuera del módulo. Todas las otras funciones (funciones auxiliares para una funcion mayor) sólo pueden ser usadas dentro del módulo[1].

En el shell de Erlang se debe especificar el módulo cargado seguido de dos puntos y la función a utilizar: modulo:funcion.

-module(math2).
-export([double/1]).

double(X) ->
   times(X, 2).
times(X, N) ->
   X * N.

double/1: tiene 1 argumento, puede ser evaluado fuera del módulo de la siguiente manera:

> math2:double(10).
20

times: tiene 2 argumentos, pero no ha sido exportada, por lo tanto al tratar de ser ejecutada el shell de Erlang responderá con un error:

> math2:times(5, 2).
** undefined function: math2:times(5,2) **

Ejecución de procesos

En este ejemplo[9] se el programa principal crea un nuevo proceso con spawn[10]. Básicamente el proceso principal crea un proceso hijo y le envía un mensaje "Hola Mundo en Erlang!" al proceso hijo. Finalmente este lo recibe y lo imprime por pantalla.

-module(procesos).
-export([hola_mundo/0, loop/0]).

hola_mundo()->
  % Ejecuta la función loop() como un nuevo proceso y guarda el id del proceso en ‘Pid’.
  Pid = spawn(fun loop/0),
  % Envía un mensaje al proceso apuntado por ‘Pid’.
  Pid ! "Hola Mundo en Erlang!".


% Cuerpo de la función loop().
loop()->
  % Recibe el mensaje enviado al proceso.
  receive Msg->
      io:format("~p~n", [Msg]) % Imprime el mensaje en la consola.
  end.

Echo

Envía mensaje del proceso A a B, B retorna el mismo mensaje a A.

Echo
Proceso de echo.

echo:start(): crea un simple proceso de echo el cual retorna cualquier mensaje enviado a el[1]:

-module(echo).                       % crea el modulo echo
-export([start/0,loop/0]).           % las funciones start y loop (ambas con 0 argumentos) pueden ser utilizadas fuera del modulo

start() ->
   spawn(echo, loop, []).            % comienza la ejecucion de echo:loop() en forma paralela a la funcion llamante

loop() ->
   receive                           % en el loop se espera recibir un mensaje
      {From, Message} ->             % trata de recivir un mensaje con el patron expresado en la siguiente linea
         From ! Message,             % envia el mensaje Message a From
         loop()
   end.

spawn(echo, loop, []): genera que la función representada por echo:loop() debe ser evaluada en paralelo de la función llamante. Entonces evaluando:

...
Id = echo:start(),
Id ! {self(), hello}
...

comienza un proceso paralelo de echo y envia el mensaje {self(), hello} al proceso self() es cual es una Built-In Function (BIF) el cual retorna el identificador del actual proceso.

Servicios

Algunos de los servicios que utilizan Erlang son:

Referencias

Herramientas personales
Espacios de nombres
Variantes
Acciones
Navegación
Herramientas