Elixir Processes
概要
Elixir の Processes について。
Exlixir のコードは Process の中で動いている。
Process はそれぞれ独立している。
Spawn
Process の生成の基本は、自動で import される spawn/1 関数を利用する方法です。
iex> pid = spawn fn -> IO.puts 1 * 2 end
2
# PID<0.76.0>
iex> self
# PID<0.54.0>
iex> Process.alive? pid
false
iex> Process.alive? self
true
iex> Process.info self
[current_function: {Process, :info, 1}, initial_call: {:erlang, :apply, 2},
status: :running, message_queue_len: 0, messages: [], links: [],
# 略
fullsweep_after: 65535, minor_gcs: 10], suspending: []]
send and receive
send/2 関数でメッセージ送信
receive/1 関数でメッセージ受信
defmodule ProcessTest do
def do_receive do
receive do
{:key, msg} -> "match " <> msg
{:other, msg} -> "not match" <> msg
after
# wait 1 sec
1_000 -> "after 1sec"
end
end
end
send self, {:key, "value"}
send self, {:other, "other"}
IO.puts ProcessTest.do_receive
IO.puts ProcessTest.do_receive
IO.puts ProcessTest.do_receive
- 出力
$ elixir process1.exs
match value
not matchother
after 1sec
- flush
iex > send self, {:key, "value"}
{:key, "value"}
iex > send self, {:other, "value"}
{:other, "value"}
iex > flush
{:key, "value"}
{:other, "value"}
:ok
Links
Process のリンクには spawn_link/1 を利用する。
spawn で例外が発生した場合
例外が伝搬されない
iex > spawn fn -> raise "oops" end
# PID<0.70.0>
04:08:03.298 [error] Error in process <0.70.0> with exit value: {#{'__exception__'=>true,'__struct__'=>'Elixir.RuntimeError',message=><<4 bytes>>},[{erlang,apply,2,[]}]}
spawn_link で例外が発生した場合
例外が伝搬される
iex > spawn_link fn -> raise "hoge raise" end
04:07:47.831 [error] Error in process <0.67.0> with exit value: {#{'__exception__'=>true,'__struct__'=>'Elixir.RuntimeError',message=><<10 bytes>>},[{erlang,apply,2,[]}]}
** (EXIT from #PID<0.54.0>) an exception was raised:
** (RuntimeError) hoge raise
:erlang.apply/2
Interactive Elixir (1.0.0) - press Ctrl+C to exit (type h() ENTER for help)
States
iex > defmodule KV do
... > def start do
... > {:ok, spawn_link(fn -> loop(%{}) end)}
... > end
... >
... > defp loop(map) do
... > receive do
... > {:get, key, caller} ->
... > send caller, Map.get(map, key)
... > loop(map)
... > {:put, key, value} ->
... > loop(Map.put(map, key, value))
... > end
... > end
... > end
{:module, KV,
<<70, 79, 82, 49, 0, 0, 6, 144, 66, 69, 65, 77, 69, 120, 68, 99, 0, 0, 0, 94, 131, 104, 2, 100, 0, 14, 101, 108, 105, 120, 105, 114, 95, 100, 111, 99, 115, 95, 118, 49, 108, 0, 0, 0, 2, 104, 2, ...>>,
{:loop, 1}}
iex >
nil
iex > {:ok, pid} = KV.start
{:ok, #PID<0.76.0>}
iex > send pid, {:get, :hoge, self()}
{:get, :hoge, #PID<0.54.0>}
iex > flush
nil
:ok
iex > send pid, {:put, :hoge, :world}
{:put, :hoge, :world}
iex > send pid, {:get, :hoge, self()}
{:get, :hoge, #PID<0.54.0>}
iex > flush
:world
:ok
iex > send pid, {:put, :hoge, :hoge_world2}
{:put, :hoge, :hoge_world2}
iex > send pid, {:put, :hige, :higeworld2}
{:put, :hige, :higeworld2}
iex > send pid, {:get, :hoge, self()}
{:get, :hoge, #PID<0.54.0>}
iex > send pid, {:get, :hige, self()}
{:get, :hige, #PID<0.54.0>}
iex > flush
:hoge_world2
:higeworld2
:ok
- プロセスを登録する方法
{:ok, pid} = KV.start
Process.register(pid, :kv)
send :kv, {:get, :hello, self()}
参照
http://elixir-lang.org/docs/stable/elixir/Process.html
http://elixir-lang.org/getting_started/11.html