概要
Elixirの対話モードでプロセスの動作を確認してみました。以下のページを参考にしました。
対話モードで実行
以下のコマンドを実行しました。
$ iex
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]
Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> spawn fn -> 1 + 2 end
#PID<0.108.0>
iex(2)> pid = self()
#PID<0.106.0>
iex(3)> Process.alive?(pid)
true
iex(4)> defmodule Example do
...(4)> def add(a, b) do
...(4)> IO.puts(a + b)
...(4)> end
...(4)> end
{:module, Example,
<<70, 79, 82, 49, 0, 0, 5, 20, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 154,
0, 0, 0, 17, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:add, 2}}
iex(5)> spawn(Example, :add, [2, 3])
5
#PID<0.120.0>
iex(6)> send self(), {:hello, "world"}
{:hello, "world"}
iex(7)> receive do
...(7)> {:hello, msg} -> msg
...(7)> {:world, msg} -> "won't match"
...(7)> end
warning: variable "msg" is unused (if the variable is not meant to be used, prefix it with an underscore)
iex:9
"world"
iex(8)> receive do
...(8)> {:hello, msg} -> msg
...(8)> after
...(8)> 1_000 -> "nothing after 1s"
...(8)> end
"nothing after 1s"
iex(9)> parent = self()
#PID<0.106.0>
iex(10)> spawn fn -> send(parent, {:hello, self()}) end
#PID<0.133.0>
iex(11)> receive do
...(11)> {:hello, pid} -> "Got hello from #{inspect pid}"
...(11)> end
"Got hello from #PID<0.133.0>"
iex(12)> send self(), :hello
:hello
iex(13)> send self(), :world
:world
iex(14)> flush()
:hello
:world
:ok
iex(15)> flush()
:ok
iex(16)> defmodule Example do
...(16)> def listen do
...(16)> receive do
...(16)> {:hello, msg} -> IO.puts(msg)
...(16)> end
...(16)> end
...(16)> end
warning: redefining module Example (current version defined in memory)
iex:16
{:module, Example,
<<70, 79, 82, 49, 0, 0, 5, 52, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 161,
0, 0, 0, 17, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:listen, 0}}
iex(17)> pid = spawn(Example, :listen, [])
#PID<0.152.0>
iex(18)> send pid, {:hello, "world"}
world
{:hello, "world"}
iex(19)> send pid, {:hello, "tokyo"}
{:hello, "tokyo"}
iex(20)> defmodule Example do
...(20)> def listen do
...(20)> receive do
...(20)> {:hello, msg} -> IO.puts(msg)
...(20)> end
...(20)> listen
...(20)> end
...(20)> end
warning: redefining module Example (current version defined in memory)
iex:20
warning: variable "listen" does not exist and is being expanded to "listen()", please use parentheses to remove the ambiguity or change the variable name
iex:25: Example.listen/0
{:module, Example,
<<70, 79, 82, 49, 0, 0, 5, 76, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 161,
0, 0, 0, 17, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:listen, 0}}
iex(21)> send pid, {:hello, "world"}
{:hello, "world"}
iex(22)> send pid, {:hello, "tokyo"}
{:hello, "tokyo"}
iex(23)> spawn fn -> raise "oops" end
#PID<0.169.0>
iex(24)>
13:50:42.004 [error] Process #PID<0.169.0> raised an exception
** (RuntimeError) oops
(stdlib 3.17) erl_eval.erl:683: :erl_eval.do_apply/6
nil
iex(25)> self()
#PID<0.106.0>
iex(26)> spawn_link fn -> raise "oops" end
** (EXIT from #PID<0.106.0>) shell process exited with reason: an exception was raised:
** (RuntimeError) oops
(stdlib 3.17) erl_eval.erl:683: :erl_eval.do_apply/6
Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
13:51:26.473 [error] Process #PID<0.173.0> raised an exception
** (RuntimeError) oops
(stdlib 3.17) erl_eval.erl:683: :erl_eval.do_apply/6
iex(1)> defmodule Example do
...(1)> def explode, do: exit(:boom)
...(1)> end
warning: redefining module Example (current version defined in memory)
iex:1
{:module, Example,
<<70, 79, 82, 49, 0, 0, 4, 208, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 151,
0, 0, 0, 16, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:explode, 0}}
iex(2)> spawn(Example, :explode, [])
#PID<0.182.0>
iex(3)> spawn_link(Example, :explode, [])
** (EXIT from #PID<0.174.0>) shell process exited with reason: :boom
Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> defmodule Example do
...(1)> def explode, do: exit(:boom)
...(1)> def run do
...(1)> Process.flag(:trap_exit, true)
...(1)> spawn_link(Example, :explode, [])
...(1)> receive do
...(1)> {:EXIT, from_pid, reason} -> IO.puts("Exit reason: #{reason}")
...(1)> end
...(1)> end
...(1)> end
warning: redefining module Example (current version defined in memory)
iex:1
warning: variable "from_pid" is unused (if the variable is not meant to be used, prefix it with an underscore)
iex:7: Example.run/0
{:module, Example,
<<70, 79, 82, 49, 0, 0, 7, 152, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 1, 2, 0,
0, 0, 28, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:run, 0}}
iex(2)> Example.run
Exit reason: boom
:ok
iex(3)> defmodule Example do
...(3)> def explode, do: exit(:boom)
...(3)> def run do
...(3)> {_pid, _ref} = spawn_monitor(Example, :explode, [])
...(3)> receive do
...(3)> {:DOWN, _ref, :process, _from_pid, reason} -> IO.puts("Exit reason: #{reason}")
...(3)> end
...(3)> end
...(3)> end
warning: redefining module Example (current version defined in memory)
iex:3
{:module, Example,
<<70, 79, 82, 49, 0, 0, 7, 144, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 241,
0, 0, 0, 26, 14, 69, 108, 105, 120, 105, 114, 46, 69, 120, 97, 109, 112, 108,
101, 8, 95, 95, 105, 110, 102, 111, 95, ...>>, {:run, 0}}
iex(4)> Example.run
Exit reason: boom
:ok
iex(5)> Task.start fn -> raise "oops" end
{:ok, #PID<0.216.0>}
iex(6)>
13:56:15.559 [error] Task #PID<0.216.0> started from #PID<0.185.0> terminating
** (RuntimeError) oops
(stdlib 3.17) erl_eval.erl:683: :erl_eval.do_apply/6
(elixir 1.12.2) lib/task/supervised.ex:90: Task.Supervised.invoke_mfa/2
(stdlib 3.17) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
Function: #Function<45.65746770/0 in :erl_eval.expr/5>
Args: []
nil
iex(7)> defmodule Math do
...(7)> def hypot(x, y) do
...(7)> :timer.sleep(3000)
...(7)> :math.sqrt(x * x + y * y)
...(7)> end
...(7)> end
{:module, Math,
<<70, 79, 82, 49, 0, 0, 5, 144, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 162,
0, 0, 0, 20, 11, 69, 108, 105, 120, 105, 114, 46, 77, 97, 116, 104, 8, 95,
95, 105, 110, 102, 111, 95, 95, 10, 97, ...>>, {:hypot, 2}}
iex(8)> task = Task.async(Math, :hypot, [3, 4])
%Task{
owner: #PID<0.185.0>,
pid: #PID<0.228.0>,
ref: #Reference<0.2269777376.2268332033.214213>
}
iex(9)> Math.hypot(5, 12)
13.0
iex(10)> Task.await(task)
5.0
iex(11)> defmodule KeyValue do
...(11)> def start_link do
...(11)> Task.start_link(fn -> loop(%{}) end)
...(11)> end
...(11)> defp loop(map) do
...(11)> receive do
...(11)> {:get, key, caller} ->
...(11)> send caller, Map.get(map, key)
...(11)> loop(map)
...(11)> {:put, key, value} ->
...(11)> loop(Map.put(map, key, value))
...(11)> end
...(11)> end
...(11)> end
{:module, KeyValue,
<<70, 79, 82, 49, 0, 0, 7, 32, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 207,
0, 0, 0, 21, 15, 69, 108, 105, 120, 105, 114, 46, 75, 101, 121, 86, 97, 108,
117, 101, 8, 95, 95, 105, 110, 102, 111, ...>>, {:loop, 1}}
iex(12)> {:ok, pid} = KeyValue.start_link
{:ok, #PID<0.249.0>}
iex(13)> send(pid, {:get, :hello, self()})
{:get, :hello, #PID<0.185.0>}
iex(14)> flush
{:EXIT, #PID<0.228.0>, :normal}
nil
:ok
iex(15)> send pid, {:put, :hello, :world}
{:put, :hello, :world}
iex(16)> send pid, {:get, :hello, self()}
{:get, :hello, #PID<0.185.0>}
iex(17)> flush
:world
:ok
iex(18)> Process.register(pid, :kv)
true
iex(19)> send :kv, {:get, :hello, self()}
{:get, :hello, #PID<0.185.0>}
iex(20)> flush
:world
:ok
iex(21)> {:ok, agent} = Agent.start_link(fn -> %{} end)
{:ok, #PID<0.259.0>}
iex(22)> Agent.update(agent, fn map -> Map.put(map, :hello, :world) end)
:ok
iex(23)> Agent.get(agent, fn map -> Map.get(map, :hello) end)
:world
iex(24)> {:ok, agent} = Agent.start_link(fn -> [1, 2, 3] end)
{:ok, #PID<0.263.0>}
iex(25)> Agent.update(agent, fn state -> state ++ [4, 5] end)
:ok
iex(26)> Agent.get(agent, &(&1 -- [2, 4]))
[1, 3, 5]
iex(27)>
まとめ
何かの役に立てばと。