Erlang-concurrency

提供:Dev Guides
移動先:案内検索

アーラン-並行性

Erlangでの並行プログラミングには、次の基本原則またはプロセスが必要です。

リストには、次の原則が含まれています-

piD = spawn(楽しい)

Funを評価する新しい並行プロセスを作成します。 新しいプロセスは、呼び出し元と並行して実行されます。 例は次のとおりです-

-module(helloworld).
-export([start/0]).

start() ->
   spawn(fun() -> server("Hello") end).

server(Message) ->
   io:fwrite("~p",[Message]).

上記のプログラムの出力は-

出力

“Hello”

Pid! メッセージ

識別子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を使用可能)と照合しようとします。これが成功すると、Expressions1を評価します。 最初のパターンが一致しない場合、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を介して生成されたプロセスに送信されます! メッセージコマンド。

上記のプログラムの出力は-

出力

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

優れた処理能力を備えたマシンでは、上記の両方のmax関数がパスします。 以下は、上記のプログラムのサンプル出力です。

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

これは、上記の受信ステートメントの仕組みです-

  • receiveステートメントを入力すると、タイマーが開始されます(ただし、式にafterセクションが存在する場合のみ)。
  • メールボックスの最初のメッセージを取得し、Pattern1、Pattern2などと照合します。 一致が成功すると、メッセージはメールボックスから削除され、パターンに続く式が評価されます。
  • receiveステートメントのパターンがメールボックスの最初のメッセージと一致しない場合、最初のメッセージはメールボックスから削除され、「保存キュー」に入れられます。次に、メールボックスの2番目のメッセージが試行されます。 この手順は、一致するメッセージが見つかるか、メールボックス内のすべてのメッセージが検査されるまで繰り返されます。
  • メールボックス内のメッセージがどれも一致しない場合、プロセスは中断され、新しいメッセージがメールボックスに次に配置されるときに実行のために再スケジュールされます。 新しいメッセージが到着しても、保存キュー内のメッセージは再照合されないことに注意してください。新しいメッセージのみが一致します。
  • メッセージが一致するとすぐに、保存キューに入れられたすべてのメッセージは、プロセスに到着した順序でメールボックスに再入力されます。 タイマーが設定されている場合、クリアされます。
  • メッセージを待っているときにタイマーが経過した場合は、ExpressionsTimeout式を評価し、保存されたメッセージをプロセスに到着した順にメールボックスに戻します。