概述 elixir 本身是一種 immutable 的語言,預設情況下,進程間是不共用任何狀態的,進程之間通過消息來交互。 而 Agent 則封裝了一種進程間共用狀態的方式,通過這種方式,不用顯式的寫 send/receieve 的代碼,就能方便的在進程之間共用狀態。 使用方法 不用 Agent 來 ...
概述
elixir 本身是一種 immutable 的語言,預設情況下,進程間是不共用任何狀態的,進程之間通過消息來交互。
而 Agent 則封裝了一種進程間共用狀態的方式,通過這種方式,不用顯式的寫 send/receieve 的代碼,就能方便的在進程之間共用狀態。
使用方法
不用 Agent 來管理狀態
首先,看一個在不用 Agent 的情況下,如何獲取進程狀態的例子。
defmodule WithoutAgent do
def start do
Map.new()
end
def get(map, key) do
if Map.has_key?(map, key) do
Map.get(map, key)
else
nil
end
end
def put(map, key, val) do
Map.put(map, key, val)
end
def delete(map, key) do
Map.delete(map, key)
end
end
測試 WithoutAgent 的使用:
iex> m = WithoutAgent.start
%{}
iex> WithoutAgent.get(m, "map-key")
nil
iex> m = WithoutAgent.put(m, "map-key", "map-val")
%{"map-key" => "map-val"}
iex> WithoutAgent.get(m, "map-key")
"map-val"
iex> m = WithoutAgent.delete(m, "map-key")
%{}
iex> m = WithoutAgent.get(m, "map-key")
nil
從上面的使用可以看出,為了使用 WithoutAgent 中的狀態(一個 map),外部還必須要自己管理 WithoutAgent 的返回的狀態 m,
通過 WithoutAgent 來改變狀態時,每次都要將當前狀態 m 作為一個參數傳給 WithoutAgent。
只有一個進程使用 WithoutAgent 時,上述方式沒有什麼問題,當有多個進程使用 WithoutAgent,每個進程持有的狀態 m 很難保持一致。
使用 Agent 來管理狀態
elixir 中的 Agent 其實並不是 elixir 發明的新東西,而是封裝了 erlang OTP 中現有的 ETS (Erlang Term Storage)
使用 Agent 來重新實現上面的例子:
defmodule WithAgent do
def start do
Agent.start_link(fn -> Map.new end, name: __MODULE__)
end
def get(key) do
Agent.get(__MODULE__, fn map ->
if Map.has_key?(map, key) do
Map.get(map, key)
else
nil
end
end)
end
def put(key, val) do
Agent.update(__MODULE__, &Map.put(&1, key, val))
end
def delete(key) do
Agent.get_and_update(__MODULE__, fn map ->
if Map.has_key?(map, key) do
Map.pop(map, key)
else
nil
end
end)
end
end
測試 WithAgent 的使用:
iex> WithAgent.start
{:ok, #PID<0.108.0>}
iex> WithAgent.get("map-key")
nil
iex> WithAgent.put("map-key", "map-val")
:ok
iex> WithAgent.get("map-key")
"map-val"
iex> WithAgent.delete("map-key")
"map-val"
iex> WithAgent.get("map-key")
nil
從上面的使用中可以看出,使用了 Agent 之後,使用方完全不用自己管理 WithAgent 的狀態,只要操作狀態即可。
這樣,多個進程同時使用 WithAgent 時,也不用管狀態衝突的事情,狀態如果有衝突也是在 WithAgent 中自己管理。
總結
總的來說,Agent 就是狀態的簡單的封裝,方便進程間狀態的共用。
此外,除了上面用的方法,Agent 中的所有方法參照:Agent