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

Erlang 并发

Erlang 的并发编程需要遵循以下基本原则或过程。

列表包括以下原则:

piD = spawn(Fun)

创建一个评估 Fun 的新并发进程。新进程与调用方并行运行。一个实例如下-

Beispiel

-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 向进程发送消息。消息发送是异步的。发送者不会等待,而是继续它正在做的事情。“!’被称为发送运算符。

一个实例如下-

Beispiel

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

Receive…end

Receive messages that have been sent to the process. It has the following syntax-

Grammatik

empfangen
Muster1 [wenn Guard1] ->
Ausdrücke1;
Muster2 [wenn Guard2] ->
Ausdrücke2;
...
End

When a message arrives at the process, the system tries to match it with Pattern1Matching (may have Guard 1). If successful, evaluate the Expressions1Evaluation. If the first pattern does not match, try using Pattern2and so on. If no pattern matches, save the message for future processing, and then the process waits for the next message.

The following program shows the use of all3An example of the entire process of issuing a command.

Beispiel

-module(helloworld). 
-export([loop/0, start/0]). 
loop() ->
   empfangen 
      {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}.

The following points should be noted about the above program:

  • The loop function has a receiving loop. Therefore, when a message is sent, it will be processed by the receiving loop.

  • Generate a new process that will go to the loop function.

  • Messages are sent to the generated process using the Pid! message command.

The output of the above program is-

Output

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), 
   {_, Zeit1} = statistics(runtime), 
   {_, Zeit2} = statistics(wall_clock), lists:foreach(fun(Pid) -> Pid ! sterben end, L), 
   
   U1 = Zeit1 * 1000 / N, 
   U2 = Zeit2 * 1000 / N, 
   io:format("Prozess spawn Zeit=~p (~p) Mikrosekunden~n", [U1, U2]).
   warten() -> 
   
   empfangen 
      sterben -> void 
   end. 
 
für(N, N, F) -> [F()]; 
für(I, N, F) -> [F()|für(I+1, N, F)]. 
start().->
   max(1000), 
   max(100000).

Auf jedem gut funktionierenden Computer passieren die beiden obigen maximalen Funktionen. Hier ist ein Beispiel für die Ausgabe des obigen Programms.

Maximal erlaubte Prozesse:262144
Prozess spawn Zeit=47.0 (16.0) Mikrosekunden
Maximal erlaubte Prozesse:262144
Prozess spawn Zeit=12.81 (10.15) Mikrosekunden

Zeitüberschreitungsempfang

Manchmal kann ein receive-Statement für immer auf eine nie eintreffende Nachricht warten. Dies kann viele Gründe haben. Zum Beispiel könnte es in unserem Programm logische Fehler geben oder der Prozess, der uns Nachrichten senden soll, könnte bereits vor dem Senden des Nachrichten abgestürzt sein. Um dieses Problem zu vermeiden, können wir eine Zeitüberschreitung im receive-Statement hinzufügen. Dies stellt die maximale Zeit ein, die der Prozess für die Wartezeit auf eine empfangene Nachricht einstellen kann.

Hier ist die Grammatik des Empfangs von Nachrichten mit Zeitüberschreitung.

Grammatik

empfangen 
Muster1 [wenn Guard1] -> 
Ausdrücke1; 
Muster2 [wenn Guard2] ->
Ausdrücke2; 
... 
nach Zeit -> 
Ausdrücke 
end

Der einfachste Beispiel ist die Erstellung einer sleeper-Funktion, wie im folgenden Programm gezeigt.

Beispiel

-module(helloworld). 
-export([sleep/1,start/0]). 
sleep(T) ->
   empfangen 
   nach T -> 
      wahr 
   end. 
   
start().->
   sleep(1000).

Der obige Code wird vor dem tatsächlichen Beenden schlafen1000 Millisekunden.

auswählender Empfang

Jeder Prozess in Erlang hat eine zugeordnete E-Mailbox. Wenn Sie eine Nachricht an diesen Prozess senden, wird die Nachricht in die E-Mailbox eingefügt. Diese E-Mailbox wird nur überprüft, wenn das Programm das Empfangsstatement bewertet.

Hier ist die allgemeine Grammatik des "auswählenden Empfangs"-Statements.

Grammatik

empfangen 
Muster1 [wenn Guard1] ->
Ausdrücke1; 
Muster2 [wenn Guard1] ->
Ausdrücke1; 
... 
nach 
Zeit ->
ExpressionTimeout 
end

Dies ist die Arbeitsweise des obigen Empfangsstatements-

  • Wenn wir einen receive-Ausdruck eingeben, starten wir einen Timer (vorausgesetzt, es gibt einen after-Abschnitt im Ausdruck).

  • mit der ersten E-Mail im Briefkasten und versuchen, sie mit Muster zu übereinstimmen1,Muster2Warten. Wenn eine Übereinstimmung erfolgreich ist, wird das E-Mail aus dem Briefkasten gelöscht und der Ausdruck nach dem Muster bewertet.

  • Wenn kein Muster im receive-Ausdruck mit der ersten Nachricht im Briefkasten übereinstimmt, wird die erste Nachricht aus dem Briefkasten gelöscht und in die 'Speicherwarteschlange' eingefügt. Versuchen Sie dann die zweite Nachricht im Briefkasten. Wiederholen Sie diesen Vorgang, bis eine Übereinstimmung gefunden oder alle Nachrichten im Briefkasten überprüft wurden.

  • Wenn alle Briefe im Briefkasten nicht gematcht werden, wird der Prozess angehalten und wird bei der nächsten Einfügung eines neuen Briefes in den Briefkasten neu geplant. Beachten Sie, dass bei Empfang neuer Nachrichten Nachrichten in der Speicherwarteschlange nicht neu gematcht werden; nur die neue Nachricht wird gematcht.

  • Sobald eine Nachricht gematcht wurde, werden alle Nachrichten, die in die Speicherwarteschlange eingefügt wurden, in der Reihenfolge ihres Eintreffens neu in den Briefkasten eingefügt. Wenn ein Timer gesetzt wurde, wird er gelöscht.

  • Wenn der Timer abgelaufen ist, während Sie auf eine Nachricht warten, bewerten Sie den Ausdruck ExpressionsTimeout und geben Sie alle gespeicherten Nachrichten in der Reihenfolge ihres Eintreffens zurück in den Briefkasten.