aprendiendo ( Erlang ).

martes, 7 de junio de 2011

Comunicación entre procesos (Ping-Pong).

| 0 comentarios |

Un ejemplo típico para explicar el funcionamiento de la comunicación entre procesos suele ser el Ping-Pong. Este consiste en dos procesos uno Ping y otro Pong. El proceso Ping envía un mensaje a Pong y este le responde.
Veamos el código:
-module(ping_pong).

-export([start/0, start/1, ping/2, pong/0]).

start() ->
    start(10).

start(Max) -> 
    Pong = spawn(ping_pong, pong, []),
    Ping = spawn(ping_pong, ping, [Pong, Max]),
    Ping ! pong,
    ok.

ping(Pong, Max) ->
    receive
        pong when Max > 0 ->
            io:format("Ping~n", []),
            Pong ! {self(), ping},
            ping(Pong, Max -1);
        _ ->
            Pong ! terminar,
            io:format("Hecho~n")
    end.

pong() ->
    receive
        {Ping, ping} ->
            io:format("Pong~n", []),
            Ping ! pong,
            pong();
        _ ->
            void
    end.
En la función start/1 arrancamos los dos procesos. En este caso, he utilizado la función spawn/3 ya que me permite pasar parámetros a la función proceso, su sintaxis es spawn(Módulo, Función, Lista_parametros). El proceso Pong no tiene parámetros, pero el proceso Ping tiene como parametros la referencia al proceso Pong y el número de veces que hay que mandar el mensaje.
La función del proceso Ping envía un mensaje ping al proceso Pong, cuando el contador no ha llegado a cero. El mensaje ping es una tupla que consta de la referencia del proceso Ping y el átomo ping, así cuando el proceso Pong reciba el mensaje sabrá a quién responder. El proceso, cada vez que envía un mensaje ping reduce en 1 el contado. En el caso, de que el contador llegue a cero envía un mensaje terminar al proceso Pong.
La función del proceso Pong acepta los mensaje enviado por el Ping y le responde con un mensaje pong. Si recibe otro mensaje que no sea ping termina.
Veamos su comportamiento:
1> c(ping_pong). 
{ok,ping_pong}
2> ping_pong:start(3).
Ping
ok
Pong
Ping
Pong
Ping
Pong
Hecho
Pero, te preguntaras ¿qué pasa cuando no hay sólo dos procesos?. Pues bien, para ello he preparado una variante del ping-pong en la que un proceso Pong tiene que responder a N procesos Ping. Veamos como queda:
-module(ping_pong2).

-export([start/0, start/2, ping/3, pong/1]).

start() ->
    start(3, 3).

start(Max, NumPing) -> 
    Pong = spawn(ping_pong2, pong, [NumPing]),
    F = fun(I) -> 
                Ping = spawn(ping_pong2, ping, [I, Pong, Max]),
                Ping ! pong
        end,
    lists:foreach ( F, lists:seq(1, NumPing) ).

ping(I, Pong, Max) ->
    receive
        pong when Max > 0 ->
            io:format("Ping ~p ~n", [I]),
            Pong ! {self(), ping, I},
            ping(I, Pong, Max -1);
        _ ->
            Pong ! terminar,
            io:format("Terminado ~p~n", [I])
    end.

pong(NumPing) ->
    receive
        {Ping, ping, I} ->
            io:format("Pong ~p ~n", [I]),
            Ping ! pong,
            pong(NumPing);
        terminar when NumPing > 1 ->
            pong(NumPing-1);
        _ ->
            io:format("Terminado Pong~n")
    end.
Ahora, en la función start/2, creamos un Pong, responsable de responder a todos los Pings que existan, y todos los Pings establecidos en el parámetro NumPing.
La función de proceso Ping recibe además un identificador I para mayor claridad a la hora de ver los resultados. Por lo demás, funciona prácticamente igual que la versión anterior salvo por que manda el identificador I en el mensaje ping.
El Pong, para saber cuando terminar este proceso le hemos añadido un parámetro que es el número de Pings generados para el ejemplo.
3> c(ping_pong2).
{ok,ping_pong2}
4> ping_pong2:start().
Ping 1 
Ping 2 
Ping 3 
ok
Pong 1 
Pong 2 
Ping 1 
Pong 3 
Ping 2 
Pong 1 
Ping 3 
Pong 2 
Ping 1 
Pong 3 
Ping 2 
Pong 1 
Ping 3 
Pong 2 
Terminado 1
Pong 3 
Terminado 2
Terminado 3
Terminado Pong
En conclusión, la comunicación entre procesos puede ser bastante simple y por poco trabajo más podemos crear un sistema cliente/servidor. En nuestro caso, el servidor es el proceso Pong, que se encarga de despachar todas las peticiones de sus clientes, los procesos Pings.

Publicar un comentario

0 comentarios:

 
Licencia Creative Commons
Aprendiendo Erlang por Verdi se encuentra bajo una Licencia Creative Commons Atribución-NoComercial-CompartirIgual 3.0 Unported.