一、方法
数据共享的方法如下:
- 参数传递
- ETS
- DETS
- DICT(进程字典)
二、作用域
- 参数传递:在函数间共享数据
- ETS:同一节点多进程间数据共享,保存在RAM中,非持久化保存
- DETS:同一节点多进程间数据共享,保存在DISK中,持久化保存
- DICT(进程字典):保存在单一进程独立内存中,只在进程中可读写
三、原理
参数传递
Erlang的参数传递是值传递并非引用传递,所以传递时会复制一份副本
另外是原子atom的时候,erlang 的垃圾回收机制是不回收的(因为原子类型不参与垃圾回收)
效率:当数据越大时,参数传递效率越低-
ETS
ets一共有4种类型的表:set、ordered_set、bag、duplicate_bag,其中(set、bag、duplicate_bag)是由哈希结构保存,时间复杂度为O(1)
而ordered_set是由平衡二叉树结构保存,时间复杂度为O(logN)4种表的比较:
set与ordered_set比是set效率更高、bag和duplicate_bag比是duplicate_bag效率高,
因为bag要去比较是否有Value重复注意ETS是有读写锁的!而且因为数据不在进程中,所以查询时会产生一份副本
DICT(进程字典)
进程字典是动态哈希表实现的字典,因为数据内存位置与数据有对应的函数关系,所以查找起来效率很快,从而增加和删除都很快(进程字典的操作效率基于查询的效率)
另外,进程字典是无锁操作的,数据在进程中,不会产生副本DETS
DETS和ETS是相似的,DETS只有3种表,没有ordered_set、它的每个函数都会操作磁盘IO,它将数据组织为线性哈希表,效率比ETS慢
四、各自的特性(优缺点)
ETS
1、生命周期方面,当创建表的进程挂了,数据有可能丢失(除非指派给其他进程了)
2、数据方面,ets表内的数据不参与垃圾回收,只有当主动删除表或者创建表的进程退出了才会清空
3、锁方面,进程字典为无锁操作
4、操作方面,数据不在进程中,所以查询时会产生一份复制的副本、发生一次拷贝内存
5、储存大小方面,能存储的数据量取决于内存的大小DETS
1、储存大小方面,最大文件大小限制为2G
2、操作方面,每个函数都对磁盘产生操作
其余都和ETS一致DICT
1、数据方面,进程字典数据在进程中,查询没有多余的复制操作,因此效率也最快
2、锁方面,进程字典是无锁的
3、生命周期方面,和所在进程的生命周期相关
五、应用场景
1、在某个进程中频繁访问大块的数据(单进程)
进程字典>ets>mnesia(ets+dets)
2、多个进程共享某个数据(同一节点跨进程)
有两种可用方式:a.消息传递 b.ets
使用消息传递如果是大块数据的话成本太大,消息传递的流程如下:
1) 计算消息的大小,并在接收进程的内存空间中给消息分配内存;
2) 将消息的内容拷贝到接收进程的堆内存中;
3) 最后将消息的地址添加到接收进程的消息队列。
虽然ets也符合也很方便,但是如果是过多进程(成千上万)去访问同一个表会产生阻塞,因为ets有读写锁,他保证每一个操作都是原子性和隔离性的,就好像所有隔离的操作一个接一个严格按照顺序执行。
3、多个节点内的进程共享数据(跨节点)
这个时候我认为mnesia是最好的选择,每个联通的节点上都会启动一套mnesia进程,去管理每个节点上的mnesia并会和其他节点交换数据,保证大家的数据都是一致的