[elixir! #0073] beam 內置的內存數據庫 —— ETS

在 beam 虛擬機裏,進程之間通常經過消息傳遞來溝通,而消息傳遞是須要複製而非共享的。在消息體積小,且只在少許的進程之間傳播時,是沒有什麼性能問題的。而若是咱們須要在大量進程之間共享大量的數據,那麼消息傳遞就顯得十分低效且沒有必要了。node

Erlang 很早就考慮到了這個場景,在 beam 中添加了 ETS(erlang term storage),它能夠讓不一樣進程直接共享數據。讓咱們來試試看它是如何使用的:socket

首先咱們新建一個 ETS 表,選擇命名爲 :table_a,類型採用 set,相似與哈希表。函數

:ets.new(:table_a, [:named_table, :set])

咱們能夠用 :ets.info/1 函數來查看這個表的詳細信息。工具

iex(2)> :ets.info :table_a
[
  id: #Reference<0.679153060.3873570820.49251>,
  read_concurrency: false,
  write_concurrency: false,
  compressed: false,
  memory: 307,
  owner: #PID<0.239.0>,
  heir: :none,
  name: :table_a,
  size: 0,
  node: :nonode@nohost,
  named_table: true,
  type: :set,
  keypos: 1,
  protection: :protected
]

注意到這裏和 socket 同樣,都需有一個進程做爲 owner,以綁定 erlang 進程世界與外界(ets,port等)的關係,從而使 link 和 mointor 機制能夠延展到這些外界部件上來。一旦 owner crash,ets表也會隨之消失。性能

":set" 類型的使用方式和 map 差很少。默認的 key 是 tuple 的第1個元素(從1開始計數)。測試

讓咱們繼續使用 BonyTrace 來測試一下,看看是否是真的不須要任何消息傳遞就能夠共享數據。spa

spawn(fn ->
      BonyTrace.start(self())

      table = :ets.new(:ets_map, [:named_table, :set, :public])

      :ets.insert(table, {"key1", "value1"})

      spawn(fn ->
        [{"key1", "value1"}] = :ets.lookup(table, "key1")
      end)

      :timer.sleep(5000)
    end)

注意 ets table 必需要設置爲 :public 才能夠讓其它進程訪問。執行完畢看到只打印出了計時器 timeout 的消息。因此ets 確實是很方便的進程間數據共享工具。code

#PID<0.331.0> RECEIVED                                 +0.000000s
MESSAGE: :timeout
相關文章
相關標籤/搜索