Elixir 狀態(tài)

2023-12-15 14:03 更新

目前我們還沒(méi)有講過(guò)狀態(tài).如果你的應(yīng)用需要狀態(tài),比如說(shuō),來(lái)保存你的應(yīng)用設(shè)置,或你需要解讀一個(gè)文件并保存在內(nèi)存中,你該如何存放它們?

最通常的答案是進(jìn)程.我們可以編寫(xiě)一個(gè)無(wú)限循環(huán)的進(jìn)程來(lái)保存狀態(tài),收發(fā)信息.例如,讓我們來(lái)編寫(xiě)一個(gè)模塊,內(nèi)容是開(kāi)啟一個(gè)像鍵值對(duì)一樣運(yùn)作的進(jìn)程,存放在?kv.exs?文件中:

defmodule KV do
  def start_link do
    Task.start_link(fn -> loop(%{}) end)
  end

  defp loop(map) do
    receive do
      {:get, key, caller} ->
        send caller, Map.get(map, key)
        loop(map)
      {:put, key, value} ->
        loop(Map.put(map, key, value))
    end
  end
end

注意start_link函數(shù)開(kāi)啟了一個(gè)運(yùn)行loop/1函數(shù)的新進(jìn)程,參數(shù)是一個(gè)空映射.loop/1函數(shù)等待著信息,并且對(duì)每個(gè)信息做出合適的反應(yīng).當(dāng)匹配到:get信息時(shí),它會(huì)反饋給調(diào)用者一個(gè)信息并再次調(diào)用loop/1,等待新的信息.當(dāng):put信息以新版本的映射調(diào)用了loop/1時(shí),給定的keyvalue就被存儲(chǔ)了.

讓我們?cè)囍\(yùn)行iex kv.exs:

iex> {:ok, pid} = KV.start_link
#PID<0.62.0>
iex> send pid, {:get, :hello, self()}
{:get, :hello, #PID<0.41.0>}
iex> flush
nil
:ok

一開(kāi)始,進(jìn)程映射中沒(méi)有鍵,所以發(fā)送一個(gè):get信息,然后刷新當(dāng)前進(jìn)程的收件箱會(huì)得到nil.讓我們發(fā)送一個(gè):put信息并再試一次:

iex> send pid, {:put, :hello, :world}
{:put, :hello, :world}
iex> send pid, {:get, :hello, self()}
{:get, :hello, #PID<0.41.0>}
iex> flush
:world
:ok

注意進(jìn)程是如何保存狀態(tài)的,以及我們可以通過(guò)向進(jìn)程發(fā)送信息來(lái)獲取和更新這個(gè)狀態(tài).事實(shí)上我們可以向任何已知pid的進(jìn)程發(fā)送信息并操作狀態(tài).

也可以用一個(gè)名字注冊(cè)pid,并允許任何知道這個(gè)名字的人發(fā)送信息給它:

iex> Process.register(pid, :kv)
true
iex> send :kv, {:get, :hello, self()}
{:get, :hello, #PID<0.41.0>}
iex> flush
:world
:ok

使用進(jìn)程存放狀態(tài),以及名字注冊(cè)在Elixir中都是非常普遍的模式.然而,通常我們不會(huì)像上面那樣手工操作這些模式,而是使用Elixir裝載的一些抽象工具.例如,Elixir提供了代理,它是狀態(tài)的一種簡(jiǎn)單抽象:

iex> {:ok, pid} = Agent.start_link(fn -> %{} end)
{:ok, #PID<0.72.0>}
iex> Agent.update(pid, fn map -> Map.put(map, :hello, :world) end)
:ok
iex> Agent.get(pid, fn map -> Map.get(map, :hello) end)
:world

Agent.start_link/2可以設(shè)置:name選項(xiàng),并且會(huì)自動(dòng)注冊(cè).除了代理,Elixir還提供了用于創(chuàng)建通用服務(wù)器(GenServer),任務(wù)等等的API,它們的底層都是由進(jìn)程支持的.我們將在Mix和OTP入門(mén)中沿著管理者樹(shù)仔細(xì)探索,同時(shí)從頭到尾創(chuàng)建一個(gè)完整的Elixir應(yīng)用.


以上內(nèi)容是否對(duì)您有幫助:
在線(xiàn)筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)