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

Concorrência do Erlang

A programação concorrente no Erlang deve seguir os seguintes princípios básicos ou processos.

A lista inclui os seguintes princípios:

piD = spawn(Fun)

Cria um novo processo concorrente para avaliar a Fun. O novo processo roda paralelamente ao chamador. Um exemplo a seguir-

Exemplo

-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 mensagens para o processo usando o identificador Pid. A envio de mensagens é assíncrono. O remetente não espera, mas continua o que estava fazendo. "!" é chamado de operador de envio.

Um exemplo a seguir-

Exemplo

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

Receive…end

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

Sintaxe

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

When a message arrives at the process, the system tries to match it with Pattern1 1“). If successful1Evaluation. 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.

Exemplo

-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}.

The following points should be noted about the above program:

  • 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 go 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).

Em qualquer máquina com boa capacidade de processamento, as duas funções máximas acima passarão. A seguir está um exemplo de saída do programa acima.

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

Recebimento com timeout

Às vezes, a sentença receive pode esperar eternamente por uma mensagem que nunca aparecerá. Isso pode ter muitos motivos. Por exemplo, pode haver erros lógicos em nosso programa ou o processo que deve nos enviar a mensagem pode ter falhado antes de enviar a mensagem.

A seguir está a sintaxe especificada para receber mensagens com timeout.

Sintaxe

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

O exemplo mais simples é criar uma função sleeper, conforme o programa a seguir.

Exemplo

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

O código acima dormirá antes de realmente sair1000 milissegundos.

Recebimento seletivo

Cada processo no Erlang tem um correio associado. Quando você envia uma mensagem para esse processo, a mensagem é colocada no correio. Apenas quando a avaliação da sentença de recebimento é feita pelo programa, é verificado esse correio.

A seguir está a sintaxe geral da sentença de recebimento seletivo.

Sintaxe

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

Isso é a maneira como a sentença de recebimento mencionada acima funciona-

  • Quando introduzimos uma sentença receive, iniciamos um temporizador (mas apenas se a expressão contiver uma seção after).

  • com o primeiro e-mail na caixa de entrada e tentar combiná-lo com o Padrão1,Padrão2Esperando correspondência. Se a correspondência for bem-sucedida, a mensagem será removida da caixa de entrada e avaliada a expressão após o padrão.

  • Se nenhum padrão na sentença receive correspondente à primeira mensagem na caixa de entrada, remova a primeira mensagem da caixa de entrada e coloque-a na 'Fila de Salvamento'. Em seguida, tente a segunda mensagem na caixa de entrada. Repita este processo até encontrar uma mensagem correspondente ou verificar todas as mensagens na caixa de entrada.

  • Se todas as mensagens na caixa de entrada não correspondem, o processo será suspenso e reprogramado para a próxima vez que uma nova mensagem for colocada na caixa de entrada. Observe que, quando uma nova mensagem é recebida, as mensagens na fila de salvamento não serão reencontradas; apenas a mensagem nova será correspondida.

  • Assim que uma mensagem for correspondida, todas as mensagens colocadas na fila de salvamento serão reintroduzidas na caixa de entrada na ordem do processo de chegada. Se foi configurado um temporizador, remova-o.

  • Se o temporizador já passou enquanto estava aguardando uma mensagem, avalie a expressão ExpressionsTimeout e coloque todas as mensagens salvas de volta na caixa de entrada na ordem do processo de chegada.