Учебники

Erlang — параллелизм

Параллельное программирование в Erlang должно иметь следующие основные принципы или процессы.

Список включает в себя следующие принципы —

piD = spawn (Fun)

Создает новый параллельный процесс, который оценивает Fun. Новый процесс выполняется параллельно с вызывающей стороной. Пример таков:

пример

Live Demo

-module(helloworld). 
-export([start/0]). 

start() ->
   spawn(fun() -> server("Hello") end). 

server(Message) ->
   io:fwrite("~p",[Message]).

Выход вышеуказанной программы —

Выход

“Hello”

Пид! Сообщение

Посылает сообщение процессу с идентификатором Pid. Отправка сообщения асинхронная. Отправитель не ждет, а продолжает то, что делал. ‘!’ называется оператором отправки.

Пример таков:

пример

Live Demo

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

server(Message) ->
   io:fwrite("~p",[Message]).

Получите … конец

Получает сообщение, которое было отправлено процессу. Он имеет следующий синтаксис —

Синтаксис

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

Когда сообщение поступает в процесс, система пытается сопоставить его с шаблоном Pattern1 (с возможной защитой Guard1); если это успешно, это оценивает Выражения1. Если первый шаблон не совпадает, он пытается Pattern2, и так далее. Если ни один из шаблонов не совпадает, сообщение сохраняется для последующей обработки, и процесс ожидает следующего сообщения.

Пример всего процесса со всеми 3 командами показан в следующей программе.

пример

Live Demo

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

Следующие вещи должны быть отмечены о вышеупомянутой программе —

  • Функция цикла имеет цикл приема конца. Поэтому, когда сообщение отправлено, оно будет обработано в конце цикла приема.

  • Появляется новый процесс, который переходит к функции цикла.

  • Сообщение отправляется порожденному процессу через Pid! команда сообщения.

Функция цикла имеет цикл приема конца. Поэтому, когда сообщение отправлено, оно будет обработано в конце цикла приема.

Появляется новый процесс, который переходит к функции цикла.

Сообщение отправляется порожденному процессу через Pid! команда сообщения.

Выход вышеуказанной программы —

Выход

Area of the Rectangle is 60

Максимальное количество процессов

При одновременном выполнении важно определить максимальное количество процессов, разрешенных в системе. После этого вы сможете понять, сколько процессов может одновременно выполняться в системе.

Давайте рассмотрим пример того, как мы можем определить, какое максимальное количество процессов может выполняться в системе.

Live Demo

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

На любой машине, которая имеет хорошую вычислительную мощность, обе вышеуказанные функции максимума пройдут. Ниже приведен пример вывода из вышеуказанной программы.

Maximum allowed processes:262144
Process spawn time=47.0 (16.0) microseconds
Maximum allowed processes:262144
Process spawn time=12.81 (10.15) microseconds

Получить с тайм-аутом

Иногда оператор получения может ждать сообщения, которое никогда не приходит. Это может быть по ряду причин. Например, в нашей программе может быть логическая ошибка, или процесс, который собирался отправить нам сообщение, мог произойти сбой до отправки сообщения. Чтобы избежать этой проблемы, мы можем добавить тайм-аут в оператор получения. Это устанавливает максимальное время, в течение которого процесс будет ожидать получения сообщения.

Ниже приводится синтаксис полученного сообщения с указанным таймаутом.

Синтаксис

receive 
Pattern1 [when Guard1] -> 
Expressions1; 

Pattern2 [when Guard2] ->
Expressions2; 
... 
after Time -> 
Expressions 
end

Простейшим примером является создание функции спящего, как показано в следующей программе.

пример

-module(helloworld). 
-export([sleep/1,start/0]). 

sleep(T) ->
   receive 
   after T -> 
      true 
   end. 
   
start()->
   sleep(1000).

Выше код будет спать в течение 1000 мс перед фактическим выходом.

Выборочный прием

Каждый процесс в Erlang имеет связанный почтовый ящик. Когда вы отправляете сообщение процессу, оно помещается в почтовый ящик. Единственный раз, когда этот почтовый ящик проверяется, это когда ваша программа оценивает оператор получения.

Ниже приведен общий синтаксис оператора выборочного получения.

Синтаксис

receive 
Pattern1 [when Guard1] ->
Expressions1; 

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

Вот как работает вышеприведенный оператор получения —

Когда мы вводим оператор получения, мы запускаем таймер (но только если в выражении присутствует раздел после).

Возьмите первое сообщение в почтовом ящике и попробуйте сопоставить его с шаблоном Pattern1, Pattern2 и т. Д. Если совпадение успешно, сообщение удаляется из почтового ящика, и выражения, следующие за шаблоном, оцениваются.

Если ни один из шаблонов в операторе получения не соответствует первому сообщению в почтовом ящике, то первое сообщение удаляется из почтового ящика и помещается в «очередь сохранения». Затем пробуется второе сообщение в почтовом ящике. Эта процедура повторяется до тех пор, пока не будет найдено соответствующее сообщение или пока все сообщения в почтовом ящике не будут проверены.

Если ни одно из сообщений в почтовом ящике не совпадает, то процесс приостанавливается и будет перенесен на выполнение при следующем добавлении нового сообщения в почтовый ящик. Обратите внимание, что при поступлении нового сообщения сообщения в очереди сохранения не сопоставляются; только новое сообщение соответствует.

Как только сообщение сопоставлено, все сообщения, помещенные в очередь сохранения, повторно вводятся в почтовый ящик в порядке их поступления в процесс. Если таймер был установлен, он очищается.

Если таймер истекает, когда мы ждем сообщения, то оцениваем выражения ExpressionsTimeout и помещаем любые сохраненные сообщения обратно в почтовый ящик в том порядке, в котором они поступили в процессе.