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を使用してプロセスにメッセージを送信します。メッセージの送信は非同期です。送信者は待機しませんが、実行していたことを続行します。‘!’ 送信演算子と呼ばれます。
例は次のとおりです-
例
-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
メッセージがプロセスに到着すると、システムはそのメッセージをパターン1と照合しようとします(ガードガード1の可能性があります)。これが成功すると、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).
優れた処理能力を備えたマシンでは、上記の最大機能の両方が合格します。以下は、上記のプログラムからの出力例です。
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ステートメントは、決して来ないメッセージを永遠に待つ場合があります。これにはいくつかの理由が考えられます。たとえば、プログラムに論理エラーがあるか、メッセージを送信しようとしていたプロセスが、メッセージを送信する前にクラッシュした可能性があります。この問題を回避するために、receiveステートメントにタイムアウトを追加できます。これにより、プロセスがメッセージの受信を待機する最大時間が設定されます。
以下は、タイムアウトが指定された受信メッセージの構文です。
構文
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).
上記のコードは、実際に終了する前に1000M秒間スリープします。
選択的受信
Erlangの各プロセスにはメールボックスが関連付けられています。プロセスにメッセージを送信すると、メッセージはメールボックスに入れられます。このメールボックスが検査されるのは、プログラムが受信ステートメントを評価するときだけです。
以下は、Selectivereceiveステートメントの一般的な構文です。
構文
receive
Pattern1 [when Guard1] ->
Expressions1;
Pattern2 [when Guard1] ->
Expressions1;
...
after
Time ->
ExpressionTimeout
end
これが上記のreceiveステートメントの仕組みです-
receiveステートメントを入力すると、タイマーが開始されます(ただし、式にafterセクションが存在する場合のみ)。
メールボックスの最初のメッセージを取得し、Pattern1、Pattern2などと照合してみてください。一致が成功すると、メッセージはメールボックスから削除され、パターンに従った式が評価されます。
receiveステートメントのどのパターンもメールボックスの最初のメッセージと一致しない場合、最初のメッセージはメールボックスから削除され、「保存キュー」に入れられます。次に、メールボックスの2番目のメッセージが試行されます。この手順は、一致するメッセージが見つかるまで、またはメールボックス内のすべてのメッセージが検査されるまで繰り返されます。
メールボックス内のどのメッセージも一致しない場合、プロセスは一時停止され、次に新しいメッセージがメールボックスに配置されたときに実行するように再スケジュールされます。新しいメッセージが到着しても、保存キュー内のメッセージは再照合されないことに注意してください。新しいメッセージのみが一致します。
メッセージが一致するとすぐに、保存キューに入れられたすべてのメッセージは、プロセスに到着した順序でメールボックスに再入力されます。タイマーが設定されている場合は、クリアされます。
メッセージの待機中にタイマーが経過した場合は、ExpressionsTimeout式を評価し、保存されたメッセージをプロセスに到着した順序でメールボックスに戻します。