7

文档说

make_ref() -> ref()  

返回一个几乎唯一的引用。

返回的引用将在大约 2 82次调用后重新出现;因此它对于实际用途来说是独一无二的。

但我的眼睛告诉我,在 VM 重新启动之间,我可以轻松获得相同的 ref:

[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>
2> make_ref().
#Ref<0.0.0.37>
^C

[~] erl
Erlang R14B04 (erts-5.8.5)
1> make_ref().
#Ref<0.0.0.33>

那么,Erlang 的 Refs 有多独特呢?当标签在 mq 或 db 中持久存在并且可能由不同的 VM 会话生成时,它们是否适合用作唯一的“标签”生成器。

我知道 UUID 可以用于此。众所周知,pids() 是可重复的、可重用的,如果序列化然后从持久存储中加载,则绝不是唯一的。

问题是,什么是 refs()——更像是 UUID 还是更像 pids()?refs() 在节点之间是唯一的吗?重启之间?有没有关于这个话题的官方信息?

4

2 回答 2

6

与节点名称相关的引用并不意味着随机性,只是唯一性。正如您已经注意到的,它们是以循环方式创建的。此外,您是正确的事实引用仅在节点的生命周期内是唯一的。一旦重新启动 VM,就可以重复引用。

与 PID 一样,打印的引用#Ref<W.X.Y.Z>包含 - 作为它们的第一个元素 ( W) - 关于节点编号的信息:

erl -sname right
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
(right@mars)1> register(right, self()).
true
(right@mars)2> receive M -> M end.
#Ref<6793.0.0.41>
(right@mars)3> 

erl -sname left
Erlang R15B (erts-5.9) [source] [64-bit] [smp:4:4] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.9  (abort with ^G)
(left@mars)1> {right, 'right@mars'} ! make_ref().
#Ref<0.0.0.41>
(left@mars)2> 

请注意,在这种情况下W,参考是如何0在本地节点中的,6793在远程节点中。

于 2012-04-05T14:20:07.373 回答
5

在任何分布式系统中,为了能够生成唯一标识符,您必须依赖具有持久存储的中央原子 ID 生成器,或者确保在任何时间点正确配置集群。第二种情况的一个例子如下。

在分布式 Erlang 集群{node(), now()}中可以认为是唯一的。如果您可以确保您的时钟配置合理并且您不会启动两个具有相同名称的节点,您可以尝试使用{node(), now(), make_ref()},这将使冲突的可能性可以忽略不计。

于 2012-04-05T14:20:30.307 回答