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

How do I store module-level write-once state?

我有一些模块级的状态,我想写一次,然后永远不要修改。

具体来说,我有一组字符串,以后要用它来查找内容。执行此操作的有效且普通的方法是什么?

我可以创建一个始终 returns 相同集合的函数:

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

VM会优化这个,还是每次构建集合的代码都重新运行?我怀疑该系列只会获得 GCd。

在这种情况下,我是否应该将集合缓存在进程字典中,以诸如模块 md5 之类的独特内容为关键字?

Key = proplists:get_value(md5, module_info()), put(Key, my_set())

另一个解决方案是让调用者调用一个 init 函数来取回不透明的状态块,然后将该状态传递给模块中的每个函数。

编译时常量,例如您的示例列表 ["a", "b", "c"],将在加载模块时存储在旁边的常量池中,并且不会在每次 运行 表达式时重建. (在过去,列表会根据每个新调用的元素重建。)无论多么复杂(如元组列表的列表),这都适用于所有常量。但是当你调用像 sets:from_list/1 这样的函数时,编译器不能假设任何有关 sets 模块使用的表示的信息,集合将从常量列表动态构造。

虽然 ETS table 可以工作,但对于较大的常量(例如,包含许多条目的集合或映射)效率较低,因为 ETS table 具有相同的内存模型作为一个过程 - 数据通过复制写入和读取,就像通过发送消息一样。如果常量很小,复制它们和在本地重新创建它们之间的区别可以忽略不计,如果常量很大,你会浪费时间复制它们。

您想要的是一个名为持久性术语存储的相当新的功能:https://erlang.org/doc/man/persistent_term.html(自 Erlang/OTP 21)。它类似于编译时常量的处理方式,因此在查找值时不会进行复制。 (关键可能是你的模块的名称。)持久性术语几乎是一种一次写入多次读取的存储——你可以更新存储的条目,但这是一个更昂贵的操作,可能会触发全局 GC。