elixir 高可用系列(一) Agent

概述

elixir 自己是一種 immutable 的語言,默認狀況下,進程間是不共享任何狀態的,進程之間經過消息來交互。
而 Agent 則封裝了一種進程間共享狀態的方式,經過這種方式,不用顯式的寫 send/receieve 的代碼,就能方便的在進程之間共享狀態。html

使用方法

不用 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 的使用:code

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。htm

只有一個進程使用 WithoutAgent 時,上述方式沒有什麼問題,當有多個進程使用 WithoutAgent,每一個進程持有的狀態 m 很難保持一致。blog

使用 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 的使用:get

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 中本身管理。it

總結

總的來講,Agent 就是狀態的簡單的封裝,方便進程間狀態的共享。
此外,除了上面用的方法,Agent 中的全部方法參照:Agentio

來源:http://blog.iotalabs.io/table

相關文章
相關標籤/搜索