English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Concurrencia en Erlang

La programación concurrente en Erlang debe seguir los principios o procesos básicos siguientes.

La lista incluye los siguientes principios:

piD = spawn(Fun)

Crear un nuevo proceso concurrente para evaluar Fun. El nuevo proceso se ejecuta en paralelo con el llamador. Un ejemplo de instancia es-

Ejemplo

-module(helloworld). 
-export([start/0]). 
start() ->
   spawn(fun()) -> server("Hello") end). 
server(Message) ->
   io:fwrite("~p", [Message]).

The output of the above program is-

Output

"Hello"

Pid ! Message

Enviar un mensaje al proceso utilizando el identificador Pid. El envío del mensaje es asíncrono. El remitente no espera, sino que continúa lo que estaba haciendo. "!" se conoce como operador de envío.

un ejemplo de instancia es-

Ejemplo

-module(helloworld). 
-export([start/0]). 
start() -> 
   Pid = spawn(fun() -> server("Hello") end), 
   Pid ! {hello}. 
server(Message) ->
   io:fwrite("~p", [Message]).

Receive…end

Receive messages that have been sent to the process. It has the following syntax-

Sintaxis

receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
End

When a message arrives at the process, the system will try to match it with Pattern1matching (may have Guard 1). If successful, then the Expressions1Evaluation. If the first pattern does not match, try using Pattern2and so on. If no pattern matches, save the message for future processing, and then the process waits for the next message.

The following program shows the use of all3An example of the entire process of issuing commands.

Ejemplo

-module(helloworld). 
-export([loop/0, start/0]). 
loop() ->
   receive 
      {rectangle, Width, Ht} -> 
         io:fwrite("Area of rectangle is ~p~n", [Width * Ht]), 
         loop(); 
      {circle, R} ->
      io:fwrite("Area of circle is ~p~n", [3.14159 * R * R]), 
      loop(); 
   Other ->
      io:fwrite("Unknown"), 
      loop() 
   end. 
start() ->
   Pid = spawn(fun() -> loop() end), 
   Pid ! {rectangle, 6, 10}.

For the above program, the following points should be noted:

  • The loop function has a receiving end loop. Therefore, when a message is sent, it will be processed by the receiving end loop.

  • Generate a new process that will move to the loop function.

  • Messages are sent to the generated process using the Pid! message command.

The output of the above program is-

Output

Area of the Rectangle is 60

Maximum number of processes

Concurrently, it is important to determine the maximum number of processes allowed on the system. Then, you should be able to understand how many processes can be executed simultaneously on the system.

Let's see an example of how to determine the maximum number of processes that can be executed on the system.

-module(helloworld). 
-export([max/1,start/0]). 
max(N) -> 
   Max = erlang:system_info(process_limit), 
   io:format("Maximum allowed processes:~p~n", [Max]), 
   
   statistics(runtime), 
   statistics(wall_clock), 
   
   L = for(1, N, fun() -> spawn(fun() -> wait() end) end), 
   {_, Time1} = statistics(runtime), 
   {_, Time2} = statistics(wall_clock), lists:foreach(fun(Pid) -> Pid ! die end, L), 
   
   U1 = Time1 * 1000 / N, 
   U2 = Time2 * 1000 / N, 
   io:format("Process spawn time=~p (~p) microsegundos~n", [U1, U2]).
   wait() -> 
   
   receive 
      die -> void 
   end. 
 
for(N, N, F) -> [F()]; 
for(I, N, F) -> [F()|for(I+1, N, F)]. 
start()->
   max(1000), 
   max(100000).

En cualquier máquina con buena capacidad de procesamiento, las dos funciones máximas anteriores pasarán. A continuación, se muestra una salida de ejemplo del programa anterior.

Máximo permitido de procesos:262144
Process spawn time=47.0 (16.0) microsegundos
Máximo permitido de procesos:262144
Process spawn time=12.81 (10.15) microsegundos

Recepción con tiempo de expiración

A veces, la declaración receive puede esperar indefinidamente un mensaje que nunca aparecerá. Esto puede tener muchas razones. Por ejemplo, puede haber errores lógicos en nuestro programa o el proceso que nos enviará el mensaje puede haberse caído antes de enviar el mensaje. Para evitar este problema, podemos agregar un tiempo de expiración a la declaración receive. Esto establecerá el tiempo máximo que el proceso esperará para recibir el mensaje.

A continuación, se muestra la sintaxis de recepción de mensajes con tiempo de expiración especificado.

Sintaxis

receive 
Pattern1 [when Guard1] -> 
Expressions1; 
Pattern2 [when Guard2] ->
Expressions2; 
... 
after Time -> 
Expressions 
end

El ejemplo más simple es crear una función sleeper, como se muestra en el programa siguiente.

Ejemplo

-module(helloworld). 
-export([sleep/1,start/0]). 
sleep(T) ->
   receive 
   after T -> 
      true 
   end. 
   
start()->
   sleep(1000).

El código anterior se detendrá antes de salir1000 milisegundos.

Recepción selectiva

Cada proceso en Erlang tiene una bandeja de entrada asociada. Cuando envía un mensaje a este proceso, el mensaje se coloca en la bandeja de entrada. Solo se verifica esta bandeja de entrada cuando el programa evalúa la declaración de recepción.

A continuación, se muestra la sintaxis general de la declaración de recepción selectiva.

Sintaxis

receive 
Pattern1 [when Guard1] ->
Expressions1; 
Pattern2 [when Guard1] ->
Expressions1; 
... 
after 
Time ->
ExpressionTimeout 
end

Este es el modo de funcionamiento de la declaración de recepción superior-

  • Cuando introducimos una declaración receive, iniciamos un temporizador (pero solo si la expresión contiene una sección after).

  • Con el primer correo electrónico en el buzón, y tratando de que coincida con el Patrón1,Patrón2Esperando coincidencia. Si la coincidencia tiene éxito, se eliminará el correo electrónico del buzón y se evaluará la expresión después del patrón.

  • Si ninguno de los patrones en la declaración receive coincide con el primer mensaje en el buzón, se eliminará el primer mensaje del buzón y se colocará en la 'cola de guardado'. Luego, se intentará con el segundo mensaje en el buzón. Repita este proceso hasta encontrar un mensaje que coincida o se hayan revisado todos los mensajes en el buzón.

  • Si todos los correos electrónicos en el buzón no coinciden, el proceso se suspenderá y se reprogramará para la próxima vez que se coloque un nuevo correo electrónico en el buzón. Tenga en cuenta que los mensajes en la cola de guardado no se volverán a coincidir cuando se reciba un nuevo mensaje; solo se coincidirá con el nuevo mensaje.

  • Una vez que se haya coincidido con un mensaje, todos los mensajes puestos en la cola de guardado se volverán a introducir en el buzón en el orden del proceso de llegada. Si se ha configurado un temporizador, se borrará.

  • Si el temporizador ha pasado mientras se espera un mensaje, evalúe la expresión ExpressionsTimeout y coloque todos los mensajes guardados en el buzón en el orden del proceso de llegada.