erlang 如何存储模块级别的一次性写入状态?

bogh5gae  于 2022-12-08  发布在  Erlang
关注(0)|答案(1)|浏览(147)

我有一些模块级状态,我想写一次,然后永远不修改。
具体地说,我有一组字符串,我想用它来查找后面的内容。
我可以创建一个函数,它总是返回相同的集合:

my_set() -> sets:from_list(["a", "b", "c"]).

VM会对此进行优化吗?还是每次都重新运行构造集合的代码?我怀疑集合只会得到GCd。
在这种情况下,我是否应该在进程字典中缓存集合,并以模块md5之类的唯一对象为键?
Key = proplists:get_value(md5, module_info()), put(Key, my_set())
另一个解决方案是让调用者调用一个init函数来获取一个不透明的状态块,然后将该状态传递给模块中的每个函数。

m4pnthwp

m4pnthwp1#

编译时常量,比如示例列表["a", "b", "c"],将在加载模块时存储在旁边的常量池中,而不是在每次运行表达式时重新构建。(在过去,对于每个新调用,列表都将根据其元素进行重构。)这适用于所有常量,无论其有多复杂但是当你调用sets:from_list/1这样的函数时,编译器不能对sets模块所使用的表示做任何假设,而sets将从那个常量列表中动态地构造出来。
虽然ETS表可以工作,但对于较大的常数效率较低(比如,包含许多条目的集合或Map),因为ETS表具有与进程相同的内存模型--数据通过复制写入和读取,就像通过发送消息一样。如果常数很小,复制它们和在本地重新创建它们之间的差异可以忽略不计,而如果常数很大,你就浪费时间复制它们。
您需要的是一个相当新的特性,称为持久性术语存储:https://erlang.org/doc/man/persistent_term.html(自Erlang/OTP 21起)。它类似于编译时常量的处理方式,因此在查找值时没有复制。(键可以是您的模块的名称。)Persistent Term的目的是作为一个一次写入多次读取的存储-您可以更新存储的条目,但这是一个更昂贵的操作,可能会触发全局GC。

相关问题