aprendiendo ( Erlang ).

domingo, 1 de abril de 2012

Procesos (III). Recepción selectiva y no selectiva de mensajes.

| 9 comentarios |

Ya hemos vistos en otras ocasiones como trabajar con procesos. Como recibir mensajes y enviarlos. En estos casos, siempre se ha utilizado una recepción no selectiva de los mensajes. En el siguiente diagrama podemos ver el modelo no selectivo de recepción de mensajes:

Selección no selectiva

Podemos observar que el proceso que se encarga de recibir los mensajes los va ha procesar según un estricto orden de llegada. El primero en llegar se almacenará y será el primero en ser comprobado y así sucesivamente, es decir, no se ha realizado una recepción selectiva.

Recepción selectiva dependiente del PID.

Supongamos por un momento que deseamos atender a un determinado proceso y sólo a este.

Recepción selectiva por PID

Siguiendo el esquema anterior tendríamos el efecto que deseamos. En este caso tenemos en juego el pattern matching de Erlang evitando que nuestro proceso reciba mensaje de otros procesos que no sean el proceso con PID pasado por parámetros. Con este sistema podríamos y discriminando procesos de forma selectiva y priorizar ciertos procesos en decremento de otros.

Recepción selectiva por tipo de mensaje.

Ahora nuestro sistema necesita procesar mensajes en un cierto orden. Primero los mensajes de un tipo, luego los de otro y así sucesivamente y en ese orden.

Recepción selectiva por orden

Este sistema es muy común en el mundo de la programación y sobre todo se da en muchos protocolos. Supongamos un protocolo en el cual realizamos una comprobación previa para posteriormente continuar con la comunicación. También es práctico para sistemas en los cuales previamente debes identificarte.

Compartiendo el PID entre procesos.

Parémonos un momento y pensemos en el siguiente diagrama:

Recepción selectiva por orden

Si, es cierto, hemos secuenciado el trabajo. Y para ello, el proceso 1 ha tenido que pasarle al proceso 2 su PID. Y el proceso 2 ha tenido que pasarle el PID del proceso 1 al proceso 3. Y este último será el encargado devolver el resultado al proceso 1

Ahora bien, hagamos un esfuerzo por cambiar el proceso 1 por un millar de procesos proceso 1.N y el proceso 3 por algunos más proceso 3.M. En este caso, el proceso 2 se encargaría de distribuir el trabajo que recibe de los procesos 1.N a los procesos 3.M. Muy interesante este modelo verdad. Ahora mismo, se me esta ocurriendo un ejemplo muy claro "un básico balanceador de carga".

Publicar un comentario en la entrada

9 comentarios:

  1. Manuel Rubio dijo...

    Muy bueno el post!... sobre el último punto, encontré esto hace no mucho tiempo, que permite generar procesos en nodos diferentes y gestionar los envíos para hacer "workers", es muy interesante:

    http://code.google.com/p/bspawner/

  2. Verdi dijo...

    Ajjaaaa... un buen proyecto para echarle un ojo, sin lugar a dudas. Me lo he descargado para ver el código, cuando tenga un poco de tiempo ;P.

    Gracias Manuel.

  3. Cosas que ver ..... dijo...

    ".... evitando que nuestro proceso reciba mensaje de otros procesos que no sean el proceso con PID pasado por parámetros".
    No sé si me confundo, pero recibe TODOS los mensajes en su Mailbox, pero solo atenderá los que cumplen el Patrón, de estos quitará el mensaje de la Mailbox, pero los demás mensajes recibidos seguirán allí, al menos hasta que hagas flush().
    Por otro lado, gracias por tu blog, estoy empezando con Erlang y me ayuda mucho.

  4. Verdi dijo...

    Perdona por el retraso pero en las vacaciones ... bueno, ya te puedes imaginar.

    Es cierto. No estas confundido. Tienes toda la razón, es buena praxis descartar los mensajes que no sabemos, o no deseamos tratar.

    De lo que no soy partidario, es del uso de "flush/0". Para mi gusto, y es por que soy como soy, prefiero el uso de un timeout para descartar los mensajes no tratados. De esta forma, la recolección de mensajes se realiza de forma controlada en los tiempos muertos del proceso. Es decir, que le puedo realizar cualquier tipo de tratamiento como registrarlos en un log para un futuro análisis.

    Gracias por el comentario. Seguiré aprendiendo ;þ

  5. Jesús Hernández Gormaz dijo...

    Para descartar los mensajes no tratados, en lugar del timeout o del flush, no es más simple un :
    _ -> ok
    al final de receive, para descartar unicamente los que no se quiere tratar sin tener que añadir ningun after y con la seguridad de que no se eliminan mensajes que si se quieran tratar, que podria pasar si en lo que comienza a ejecutarse el flush a la vez llega un mensaje, que al ejecutarse concurrentemente creo que podria suceder. ¿Que opinais? llevo poco tiempo con erlang pero es lo que se me ha ocurrido al oir lo del flush y el timeout (que el timeout he supuesto que seria el after que permite no quedar bloqueado). Y al ser un simple ok loq ue retorna no creo que consuma demasiado tiempo de procesamiento o recursos.

  6. Verdi dijo...

    Hola Jesús.

    No se si te he entendido bien. Pero creo que propones algo como:


    receive
    mensajes -> procesar
    _ -> ok
    end


    Te propongo que hagamos el siguiente ejercicio. Tres posibles escenarios:

    * Entorno controlado: no hay riesgos de mensajes no validos o el riesgo es mínimo. En este caso, el patrón que propones funcionaría perfectamente.

    * Entorno no controlado: en el que recibes muchos mensajes que no hacen matching con tus patrones de mensajes. En este caso, estaríamos dando la misma prioridad a los mensajes validos de los no validos. Es decir, penalizaríamos la evaluación de los mensajes validos en post de los mensajes no validos. Aun así, seguiría funcionado bien.

    * Entorno no controlado (hostil): en el que el número de mensajes recibidos que no hacen matching es excesivo. En este escenario podríamos tener un bandeja de entrada de mensajes en el que los primeros mensajes (pongamos 100.000, 300.000 o más) son mensajes que no hacen matching y un último mensaje que sí. ¿Cuánto tardaría en tratar el último mensaje? ¿Se puede ralentizar el sistema? Creo ya sabrás por donde voy.

    En conclusión, podemos encontrarnos con que nuestro sistema se vuelva lento y pesado. Pasándose la mayor parte del tiempo tratando mensajes inútiles. Es por ello, por lo que se recomienda el uso del after con el uso de una función flush, como bien, indicas. El patrón típico para realizar el flush es :


    proceso() ->
    receive
    mensajes -> procesar
    after milisegundos
    flush(),
    proceso();
    end.

    flush() ->
    receive
    _ -> flush()
    after 0 ->
    ok
    end.


    Con ello conseguimos priorizar nuestros mensajes. Y nuestro sistema no se ve entorpecido por los mensajes no deseados.

    Espero no haberme extendido demasiado ;þ y haberte sido de ayuda.

  7. Jesús Hernández Gormaz dijo...

    Verdi gracias por la aclaración. Solo una duda que aun tengo, ¿durante la ejecución del flush si llega un mensaje que si queremos procesar podría tener la mala suerte de tambien ser "deborado" por el flush?

    Por cierto, aunque no viene a cuento con nada de este articulo aparte de ser sobre Erlang, ¿por casualidad sabes a que se deben las dependencias con algunos paquetes de java al instalar erlang desde el repositorio de varias distros deribadas de debian? pero que al instalarlo desde el repositorio de Erlang solutions no me pide esas dependencias de java. Fue una curiosidad que me llamo la atención.

  8. Verdi dijo...

    Hola Jesus.

    En teoría no es posible. Por ello, se tratan en el "after" para evitar este tipo de problemas.

    Con respecto, al problemas de dependencias no se exactamente que problemas tienes. No debe haber dependencias. Se que existe un paquete erlang-ic-java. No se si te refieres a él pero es independiente del erlang-base.

    Saludos.

  9. Jesús Hernández Gormaz dijo...

    Verdí gracias por la aclaración.

    Las dependencias en si no es un problema, se instalan y listo, pero me resulto extraño la dependencía de java que tienen los paquetes mantenidos en el repositorio del que los traiga linux mint y como luego no vi esa dependencia con el de erlang solutions pues me extrañe aun más. Supongo sera que algun paquete de los de erlang en linux mint hace algun tipo de "a instalar todo junto".

    Me quedo más tranquilo sabiendo Erlang no depende de Java, jejeje. ¿El erlang-ic-java es para algo de comunicacion con java o algo de eso unicamente, no?

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