Параллельное программирование в Erlang должно иметь следующие основные принципы или процессы.
Список включает в себя следующие принципы —
piD = spawn (Fun)
Создает новый параллельный процесс, который оценивает Fun. Новый процесс выполняется параллельно с вызывающей стороной. Пример таков:
пример
-module(helloworld). -export([start/0]). start() -> spawn(fun() -> server("Hello") end). server(Message) -> io:fwrite("~p",[Message]).
Выход вышеуказанной программы —
Выход
“Hello”
Пид! Сообщение
Посылает сообщение процессу с идентификатором Pid. Отправка сообщения асинхронная. Отправитель не ждет, а продолжает то, что делал. ‘!’ называется оператором отправки.
Пример таков:
пример
-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 командами показан в следующей программе.
пример
-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
Максимальное количество процессов
При одновременном выполнении важно определить максимальное количество процессов, разрешенных в системе. После этого вы сможете понять, сколько процессов может одновременно выполняться в системе.
Давайте рассмотрим пример того, как мы можем определить, какое максимальное количество процессов может выполняться в системе.
-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 и помещаем любые сохраненные сообщения обратно в почтовый ящик в том порядке, в котором они поступили в процессе.