
- 作者: Fred Hebert,山口能迪
- 出版社/メーカー: オーム社
- 発売日: 2014/07/04
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (8件) を見る
引き続き。
11.1 状態を述べろ
defmodule Kitchen do def fridge1 do receive do {{:store, food}, from} -> send from, {self(), :ok} fridge1 {{:take, food}, from} -> send from, {self(), :not_found} :terminate -> :ok end end end
実行する
ex(2)> c("ch11.ex") ch11.ex:1: warning: redefining module Kitchen ch11.ex:4: warning: variable food is unused ch11.ex:7: warning: variable food is unused ch11.ex:15: warning: variable food is unused ch11.ex:18: warning: variable food is unused [Kitchen] iex(3)> fridge1 = spawn(Kitchen, :fridge1, []) #PID<0.66.0> iex(4)> send fridge1, {{:store, :apple}, self()} {{:store, :apple}, #PID<0.57.0>} iex(5)> flush {#PID<0.66.0>, :ok} :ok iex(6)> send fridge1, {{:take, :apple}, self()} {{:take, :apple}, #PID<0.57.0>} iex(7)> flush {#PID<0.66.0>, :not_found} :ok
- 食べ物を保存する場所がない
- 状態を追加する必要がある
defmodule Kitchen do def fridge2(foodList) do receive do {{:store, food}, from} -> send from, {self(), :ok} fridge2 [food|foodList] {{:take, food}, from} -> case Enum.member? foodList, food do true -> send from, {self(), {:ok, food}} fridge2 List.delete foodList, food false -> send from, {self(), :not_found} fridge2 foodList end :terminate -> :ok end end end
- 状態を再帰で関数のパラメータに保持
iex(10)> c("ch11.ex") ch11.ex:1: warning: redefining module Kitchen ch11.ex:4: warning: variable food is unused ch11.ex:7: warning: variable food is unused [Kitchen] iex(11)> pid = spawn(Kitchen, :fridge2, [[:baking_soda]]) #PID<0.80.0> iex(12)> send pid, {{:store, :milk}, self()} {{:store, :milk}, #PID<0.57.0>} iex(13)> flush {#PID<0.80.0>, :ok} :ok iex(14)> send pid, {{:store, :bacon}, self()} {{:store, :bacon}, #PID<0.57.0>} iex(15)> send pid, {{:take, :bacon}, self()} {{:take, :bacon}, #PID<0.57.0>} iex(16)> send pid, {{:take, :turkey}, self()} {{:take, :turkey}, #PID<0.57.0>} iex(17)> flush {#PID<0.80.0>, :ok} {#PID<0.80.0>, {:ok, :bacon}} {#PID<0.80.0>, :not_found} :ok
11.2 メッセージ大好きだけど秘密にしておいて
defmodule Kitchen do def store(pid, food) do send pid, {{:store, food}, self()} receive do {pid, msg} -> msg end end def take(pid, food) do send pid, {{:take, food}, self()} receive do {pid, msg} -> msg end end def fridge2(foodList) do receive do {{:store, food}, from} -> send from, {self(), :ok} fridge2 [food|foodList] {{:take, food}, from} -> case Enum.member? foodList, food do true -> send from, {self(), {:ok, food}} fridge2 List.delete foodList, food false -> send from, {self(), :not_found} fridge2 foodList end :terminate -> :ok end end end
- メッセージの抽象化を行う
iex(18)> c("ch11.ex") ch11.ex:1: warning: redefining module Kitchen ch11.ex:5: warning: variable pid is unused ch11.ex:12: warning: variable pid is unused ch11.ex:18: warning: variable food is unused ch11.ex:21: warning: variable food is unused [Kitchen] iex(19)> pid = spawn(Kitchen, :fridge2, [[:baking_soda]]) #PID<0.94.0> iex(20)> Kitchen.store pid, :water :ok iex(21)> Kitchen.take pid, :water {:ok, :water} iex(22)> Kitchen.take pid, :juice :not_found
- startを追加
defmodule Kitchen do def start(foodList) do IO.inspect __MODULE__ spawn(__MODULE__ , :fridge2, [foodList]) end ...
iex(1)> c("ch11.ex") ch11.ex:1: warning: redefining module Kitchen ch11.ex:10: warning: variable pid is unused ch11.ex:17: warning: variable pid is unused ch11.ex:23: warning: variable food is unused ch11.ex:26: warning: variable food is unused [Kitchen] iex(2)> pid = Kitchen.start [:rhubarb, :dog, :hotdog] Kitchen #PID<0.65.0> iex(3)> Kitchen.take pid, :dog {:ok, :dog}
- Elixirではmodule名は
__MODULE__
で取れる
11.3 タイムアウト
前回やってので省略。
after
でタイムアウト指定できる。
11.4 選択的受信
defmodule MultiProc do def important do receive do {priority, msg} when priority > 10 -> [msg | important()] after 0 -> normal() end end def normal do receive do {_, msg} -> [msg | normal()] after 0 -> [] end end end
iex(1)> c("ch11.ex") ch11.ex:1: warning: redefining module Kitchen ch11.ex:10: warning: variable pid is unused ch11.ex:17: warning: variable pid is unused ch11.ex:23: warning: variable food is unused ch11.ex:26: warning: variable food is unused [MultiProc, Kitchen] iex(2)> send self(), {15, :high} {15, :high} iex(3)> MultiProc.important [:high] iex(4)> send self(), {15, :high} {15, :high} iex(5)> send self(), {17, :high} {17, :high} iex(6)> send self(), {9, :low} {9, :low} iex(7)> send self(), {5, :low} {5, :low} iex(8)> MultiProc.important [:high, :high, :low, :low]
選択的受信の落とし穴
- 無視したメッセージが多くなると読み込み時間が長くなる
- プロセスサイズも大きくなる