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

Конкурентоспособность в Erlang

Конкурентное программирование Erlang требует соблюдения следующих основных принципов или процессов.

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

piD = spawn(Fun)

Создание нового параллельного процесса для оценки Fun. Новый процесс выполняется параллельно с вызовом. Пример之一的 реализации-

Пример

-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

Сообщение отправляется в процесс с помощью идентификатора 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;
...
Конец

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

The following program shows an example of the entire process using all 3 commands.

Пример

-module(helloworld). 
-export([loop/0, start/0]). 
loop() ->
   receive 
      {rectangle, Width, Ht} -> 
         io:fwrite("The area of the rectangle is ~p~n", [Width * Ht]), 
         loop(); 
      {circle, R} ->
      io:fwrite("The area of the 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 go to the loop function.

  • Send a message to the generated process using the Pid! message command.

The output of the above program is -

Output

The 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 look at 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) 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).

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

Максимальное количество разрешенных процессов:262144
Process spawn время=47.0 (16.0) микросекунд
Максимальное количество разрешенных процессов:262144
Process spawn время=12.81 (10.15) микросекунд

Прием с timeout

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

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

Грамматика

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

Самый простой пример — это создание функции sleep, как показано в следующем примере программы.

Пример

-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

Таким образом работает上面的 способ приема сообщений-

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

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

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

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

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

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