Erlang - Simultaneidade
A programação simultânea em Erlang precisa ter os seguintes princípios ou processos básicos.
A lista inclui os seguintes princípios -
piD = spawn (divertido)
Cria um novo processo simultâneo que avalia Diversão. O novo processo é executado em paralelo com o chamador. Um exemplo é o seguinte -
Exemplo
-module(helloworld).
-export([start/0]).
start() ->
spawn(fun() -> server("Hello") end).
server(Message) ->
io:fwrite("~p",[Message]).
O resultado do programa acima é -
Resultado
“Hello”
Pid! mensagem
Envia mensagem ao processo com identificador Pid. O envio de mensagens é assíncrono. O remetente não espera, mas continua o que estava fazendo.‘!’ é chamado de operador de envio.
Um exemplo é o seguinte -
Exemplo
-module(helloworld).
-export([start/0]).
start() ->
Pid = spawn(fun() -> server("Hello") end),
Pid ! {hello}.
server(Message) ->
io:fwrite("~p",[Message]).
Receber ... fim
Recebe uma mensagem que foi enviada a um processo. Possui a seguinte sintaxe -
Sintaxe
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
End
Quando uma mensagem chega ao processo, o sistema tenta casá-la com o Padrão1 (com possível guarda Guard1); se for bem-sucedido, ele avalia Expressions1. Se o primeiro padrão não corresponder, ele tentará o Padrão2 e assim por diante. Se nenhum dos padrões corresponder, a mensagem será salva para processamento posterior e o processo aguardará a próxima mensagem.
Um exemplo de todo o processo com todos os 3 comandos é mostrado no programa a seguir.
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}.
As seguintes coisas precisam ser observadas sobre o programa acima -
A função de loop possui o loop final de recebimento. Portanto, quando uma mensagem é enviada, ela é processada pelo loop final de recebimento.
Um novo processo é gerado e vai para a função de loop.
A mensagem é enviada para o processo gerado através do Pid! comando de mensagem.
O resultado do programa acima é -
Resultado
Area of the Rectangle is 60
Número Máximo de Processos
Na simultaneidade, é importante determinar o número máximo de processos permitidos em um sistema. Você deve ser capaz de entender quantos processos podem ser executados simultaneamente em um sistema.
Vamos ver um exemplo de como podemos determinar qual é o número máximo de processos que podem ser executados em um sistema.
-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) microseconds~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 que tenha um bom poder de processamento, ambas as funções máximas acima serão aprovadas. A seguir está um exemplo de saída do programa acima.
Maximum allowed processes:262144
Process spawn time=47.0 (16.0) microseconds
Maximum allowed processes:262144
Process spawn time=12.81 (10.15) microseconds
Receber com um tempo limite
Às vezes, uma declaração de recebimento pode esperar para sempre por uma mensagem que nunca chega. Isso pode ser por uma série de razões. Por exemplo, pode haver um erro lógico em nosso programa ou o processo que iria nos enviar uma mensagem pode ter travado antes de enviar a mensagem. Para evitar esse problema, podemos adicionar um tempo limite à instrução de recebimento. Isso define um tempo máximo que o processo aguardará para receber uma mensagem.
A seguir está a sintaxe da mensagem recebida com um tempo limite especificado
Sintaxe
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard2] ->
Expressions2;
...
after Time ->
Expressions
end
O exemplo mais simples é criar uma função dormente, conforme mostrado no 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 ficará inativo por 1000 Ms antes de realmente sair.
Recebimento seletivo
Cada processo em Erlang possui uma caixa de correio associada. Quando você envia uma mensagem para o processo, a mensagem é colocada na caixa de correio. A única vez que esta caixa de correio é examinada é quando o programa avalia uma instrução de recebimento.
A seguir está a sintaxe geral da instrução de recebimento seletivo.
Sintaxe
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard1] ->
Expressions1;
...
after
Time ->
ExpressionTimeout
end
É assim que funciona a declaração de recebimento acima -
Quando inserimos uma instrução de recepção, iniciamos um cronômetro (mas apenas se uma seção posterior estiver presente na expressão).
Pegue a primeira mensagem na caixa de correio e tente compará-la com o Padrão1, Padrão2 e assim por diante. Se a correspondência for bem-sucedida, a mensagem será removida da caixa de correio e as expressões que seguem o padrão serão avaliadas.
Se nenhum dos padrões na instrução de recebimento corresponder à primeira mensagem na caixa de correio, a primeira mensagem será removida da caixa de correio e colocada em uma "fila de salvamento". A segunda mensagem na caixa de correio é então tentada. Este procedimento é repetido até que uma mensagem correspondente seja encontrada ou até que todas as mensagens na caixa de correio tenham sido examinadas.
Se nenhuma das mensagens na caixa de correio corresponder, o processo será suspenso e será reprogramado para execução na próxima vez que uma nova mensagem for colocada na caixa de correio. Observe que, quando uma nova mensagem chega, as mensagens na fila de salvamento não são correspondidas; apenas a nova mensagem é correspondida.
Assim que uma mensagem é correspondida, todas as mensagens que foram colocadas na fila de salvamento são reentradas na caixa de correio na ordem em que chegaram ao processo. Se um cronômetro foi definido, ele é apagado.
Se o cronômetro passar enquanto estamos aguardando uma mensagem, avalie as expressões ExpressionsTimeout e coloque todas as mensagens salvas de volta na caixa de correio na ordem em que chegaram ao processo.