iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0

上一篇簡單的使用 send 與 receive 達成了基於一個 process 的狀態儲存,但我們不需要每次都自己做一個,Elixir 提供了更完整的 module 叫 Agent

基本用法

與上一篇自己寫的用法類似,開啟一個 process 並給予預設值,也可以讀取與更新

{:ok, pid} = Agent.start_link(fn -> 3 end)
Agent.get(pid, fn x -> x end)
#=> 3
Agent.update(pid, fn x -> x + 3 end)
#=> :ok
Agent.get(pid, fn x -> x end)
#=> 6

name

在使用 Agent.start_link/2 時,我們可以加上 name 選項,可以指定名字 (使用 atom, 這邊通常用大寫類似模組名的模式),就可以不用存 pid 直接指定名字使用

Agent.start_link(fn -> 100 end, name: Storage)
Agent.get(Storage, fn x -> x end)
#=> 100
Agent.update(Storage, fn x -> x * 2 end)
#=> :ok
Agent.get(Storage, fn x -> x end)
#=> 200

在 Module 使用 Agent 包裝邏輯

Agent 使用函式來讀取或更新狀態給我們很多彈性,但有時候會想要包裝的簡單一點

以這個過度簡單的銀行範例來說,在包裝後使用上方便很多

defmodule Bank do
  def start_link(initial_amount) do
    Agent.start_link(fn -> initial_amount end, name: __MODULE__)
  end

  def balance do
    Agent.get(__MODULE__, fn x -> x end)
  end

  def deposit(amount) do
    Agent.update(__MODULE__, fn x -> x + amount end)
  end
end

使用方式為

Bank.start_link(300)
Bank.balance()
#=> 300
Bank.deposit(700)
#=> :ok
Bank.balance()
#=> 1000

server vs client

這裡使用 server 與 client 來指操作 Agent 的 process 與 Agent.start_link 產生的目標 (server)

依照情境可以選擇要把邏輯放在哪一端

延伸上面的銀行範例,假如每次要讀取餘額的時候,需要一個運算負擔很大的檢核函式,比起把這個函式放在 server 上,讓它變成匿名函式在 server 執行再回傳結果

def balance do
  Agent.get(__MODULE__, fn x -> expensive_examine(x) end)
end

不如放在 client 端,從 server 拿到再執行

def balance do
  Agent.get(__MODULE__, fn x -> x end) |> expensive_examine()
end

如此就算有多個 client,也比較不會塞在 server 這個 process 上


上一篇
06 用 Process 儲存狀態
下一篇
08 Task
系列文
Elixir 多工 : Processes 與 OTP15
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言