在 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