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

并发 Erlang

Le développement concurrent en Erlang doit suivre les principes ou les processus suivants.

La liste inclut les principes suivants:

piD = spawn(Fun)

Créer un nouveau processus concurrent pour évaluer Fun. Le nouveau processus s'exécute en parallèle avec l'appelant. Un exemple suivant-

Exemple

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

上面程序的输出是-

输出

"Hello"

Pid ! Message

Envoyer un message à un processus via l'identifiant Pid. L'envoi du message est asynchrone. L'envoyeur ne attend pas, mais continue de faire ce qu'il fait. "!" est appelé opérateur d'envoi.

un exemple suivant-

Exemple

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

Receive…end

接收已发送到进程的消息。它具有以下语法-

Grammaire

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

当消息到达该进程时,系统会尝试将其与Pattern1匹配(可能有Guard 1)。如果成功,则对Expressions1求值。如果第一个模式不匹配,则尝试使用Pattern2,依此类推。如果没有任何一个模式匹配,则保存该消息以供以后处理,然后该过程等待下一条消息。

以下程序显示了使用全部3个命令的整个过程的示例。

Exemple

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

关于上述程序,需要注意以下几点:

  • loop函数具有接收端循环。因此,当消息被发送时,它将被接收端循环处理。

  • 生成一个新进程,该进程将转到循环函数。

  • 通过 Pid! message 命令将消息发送到产生的进程。

上面程序的输出是-

输出

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

Sur n'importe quelle machine bien équipée, les deux fonctions maximales ci-dessus passent. Voici un exemple de sortie de ce programme.

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

Réception avec délai d'attente

Parfois, l'expression de réception peut attendre éternellement un message qui ne viendra jamais. Cela peut avoir de nombreuses raisons. Par exemple, il peut y avoir des erreurs logiques dans notre programme, ou le processus qui doit nous envoyer un message peut avoir planté avant d'envoyer le message.

Voici la grammaire de réception de message avec délai d'attente spécifié

Grammaire

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

Le cas le plus simple est de créer une fonction sleep, comme indiqué dans le programme suivant.

Exemple

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

Le code ci-dessus va s'endormir avant de quitter effectivement1000 millisecondes.

Réception sélective

Chaque processus Erlang a un boîte aux lettres associée. Lorsque vous envoyez un message à ce processus, le message est placé dans la boîte aux lettres. Ce n'est que lorsque le programme évalue l'expression de réception que ce boîte aux lettres est vérifié.

Voici la grammaire générale de l'expression de réception sélective.

Grammaire

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

C'est la manière dont fonctionne l'expression de réception ci-dessus-

  • 当我们输入一个receive语句时,我们将启动一个计时器(但前提是表达式中存在一个after节)。

  • 以邮箱中的第一封邮件,并尝试使其与Pattern1,Pattern2等匹配。如果匹配成功,将从邮箱中删除该邮件,并评估模式后面的表达式。

  • 如果receive语句中的任何模式都不匹配邮箱中的第一条消息,则将从邮箱中删除第一条消息并将其放入“保存队列”。然后尝试邮箱中的第二条消息。重复此过程,直到找到匹配的消息或检查了邮箱中的所有消息为止。

  • 如果邮箱中的所有邮件都不匹配,则该过程将被挂起,并将在下次将新邮件放入邮箱中时重新安排执行时间。请注意,当收到新消息时,保存队列中的消息将不重新匹配;仅匹配新消息。

  • 一旦匹配了一条消息,所有放入保存队列的消息就会按照到达过程的顺序重新输入到邮箱中。如果设置了计时器,则将其清除。

  • 如果在等待消息时计时器已过去,请评估表达式ExpressionsTimeout并将所有保存的消息按到达过程的顺序放回邮箱。