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

上面程序的输出是-

输出

「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…end

送信されたメッセージを受け取ります。以下の構文を持っています-

文法

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

メッセージがプロセスに到着すると、システムはそれをPattern1マッチング(Guardが可能) 1を使用して試みます。成功した場合、Expressions1評価。最初のパターンに一致しない場合、Pattern2など、どのパターンにも一致しない場合、そのメッセージを保存して以降の処理を待ちます。

以下のプログラムは、すべての3コマンド全体の処理の例です。

-module(helloworld). 
-export([loop/0, start/0]). 
loop() ->
   receive 
      {rectangle, Width, Ht} -> 
         io:fwrite("長方形の面積は~p~n", [Width * Ht]), 
         loop(); 
      {circle, R} ->
      io:fwrite("円の面積は~p~n", [3.14159 * R * R]), 
      loop(); 
   その他 ->
      io:fwrite("Unknown"), 
      loop() 
   end. 
start() ->
   Pid = spawn(fun() -> loop() end), 
   Pid ! {rectangle, 6, 10}.

このプログラムについて、以下の点に注意してください:

  • loop関数には受信端ループがあります。したがって、メッセージが送信されると、受信端ループで処理されます。

  • 新しいプロセスを生成し、それがループ関数に移行します。

  • 通过Pid! messageコマンドでメッセージを生成プロセスに送信します。

上面程序的输出是-

输出

长方形面积是 60

最大进程数

并发地,重要的是确定系统上允许的最大进程数。然后,您应该能够了解系统上可以同时执行多少个进程。

让我们看一个示例,该示例如何确定系统上可以执行的最大进程数。

-module(helloworld). 
-export([max/1,start/0]). 
max(N) -> 
   Max = erlang:system_info(process_limit), 
   io:format("最大允许进程数:~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) マイクロ秒~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 time=47.0 (16.0) マイクロ秒
許可されるプロセスの最大数:262144
Process spawn time=12.81 (10.15) マイクロ秒

タイムアウト受信

時には、receive文が決して現れないメッセージを永遠に待つことがあります。これは多くの理由が考えられます。例えば、プログラムに論理的なエラーがある場合や、メッセージを送信するプロセスがメッセージを送信する前にクラッシュしている可能性があります。この問題を避けるために、receive文にタイムアウトを追加することができます。これにより、プロセスが受信メッセージを待つ最長時間が設定されます。

以下はタイムアウトを受け取る受信文の文法です。

文法

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

最も単純な例は、以下のプログラムのようにsleeper関数を作成することです。

-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、パターン2一致待ち。一致が成功した場合、そのメールはメールボックスから削除され、パターンの後の式が評価されます。

  • receive 文で指定されたどのパターンもメールボックスの最初のメッセージに一致しない場合、最初のメッセージはメールボックスから削除され「保存キュー」に移行されます。次のメールボックスのメッセージを試みます。このプロセスを繰り返し、一致するメッセージが見つかるか、メールボックスのすべてのメッセージを確認するまで続けます。

  • メールボックスにすべてのメールが一致しない場合、そのプロセスは停止し、次に新しいメールがメールボックスに追加されたときに実行時間を再スケジュールします。ただし、新しいメッセージを受信した場合、保存キューのメッセージは再マッチされません;新しいメッセージのみがマッチされます。

  • メッセージが一致した場合、保存キューに追加されたすべてのメッセージが到着プロセスの順序でメールボックスに再入力されます。タイマーが設定されている場合、それをクリアします。

  • メッセージの待機中にタイマーが経過した場合、ExpressionsTimeout 式を評価し、すべての保存されたメッセージを到着プロセスの順序でメールボックスに戻します。