基于物理身份的Hashtbl.hash替代方案



>我正在尝试导出一个描述结构化值的Graphviz文件。 这是出于诊断目的,所以我希望我的图形尽可能接近地反映内存中的实际结构。 我正在使用以下内容将值映射到 Graphviz 顶点,以便在值具有两个或多个入站引用时可以重用顶点:

let same = (==)
module StateIdentity : Hashtbl.HashedType = struct
type t = R.meta_t state
let hash = Hashtbl.hash
let equal = same
end
module StateHashtbl = Hashtbl.Make (StateIdentity)

Hashtbl.hash的文档建议它适合在StateIdentity.equal = (=)StateIdentity.equal = (==)时使用,但我想确保哈希表访问尽可能接近 O(1),因此宁愿不要在每次查找时Hashtbl.hash遍历一个(在这种情况下可能很大)对象图。

我知道 Ocaml 会移动引用,但是 Ocaml 中是否有可用的引用标识的 O(1) 代理?

Ocaml 中可变变量的哈希表的答案表明并非如此。

我讨厌将序列号附加到状态,因为这是诊断代码,因此我所做的任何错误都有可能掩盖其他错误。

如果在 OCaml 的< ... >对象类型意义上使用单词"object",则可以使用Oo.id为每个实例获取唯一的整数标识。否则,"是否存在价值身份的一般代理"的答案是"否"。在这种情况下,我的建议是从Hashtbl.hash开始,评估它是否符合您的需求,然后设计自己的哈希函数。

您还可以使用Hashtbl.hash_param(请参阅文档)在哈希期间打开值遍历旋钮。请注意,Hashtbl 代码对相同哈希值的存储桶使用链表,因此存在大量哈希冲突将触发线性搜索行为。最好使用二叉搜索树来解决冲突桶移动到其他实现。但话又说回来,您应该在转向更复杂的解决方案(并且在"好情况下"性能更差)之前评估您的情况。

我发现使用物理相等性进行哈希处理非常棘手。 您当然不能使用诸如值地址之类的东西作为哈希键,因为(正如您所说)事物会被GC移动。 一旦你有一个哈希键,似乎你可以使用物理相等来进行比较,只要你的值是可变的。 如果您的值不可变,OCaml 不能保证 (==) 的含义。 实际上,如果 OCaml 编译器或运行时愿意,理论上可以将相等 (=) 的不可变对象合并到单个物理对象中(反之亦然)。

当我研究各种可能性时,当我需要一个唯一 id 时,我通常会在我的值中输入一个序列号。 正如 gasche 所说,如果你的值是实际的 OO 样式对象,你可以使用Oo.id

像其他人一样,我认为唯一的ID是要走的路。

唯一 ID 不难安全生成。一种解决方案是使用所谓的私有记录,如下所示。它可以防止模块的用户复制 id 字段:

模块类型 Intf = 西格 类型 t = 私有 { ID : int; foo : 字符串; } 第 create_t : foo: 字符串 -> t 结束 模块 Impl : Intf = 结构 类型 t = { ID : int; foo : 字符串; } 设create_id = 设 n = 引用 0 in 乐趣 () ->如果 !n = -1 则 失败并显示"超出唯一 ID" 否则( 增加 n; !n ) 设create_t ~foo = { id = create_id (); 噗噗�� } 结束

对不起,这个丑陋的黑客,但我前段时间做了类似的事情。

这样做的诀窍是确保值在插入表后不会在内存中移动。有两种情况可以移动内存中的值:从次要堆复制到主堆和主要堆压缩。这意味着,当您在表中插入值时,它必须位于主堆中,并且在表上的两个操作之间,必须确保没有发生压缩。

可以使用 C 函数is_young检查值是否在次要堆中,如果是这种情况,您可以使用 Gc.minor () 强制值迁移到主堆。

对于第二个问题,您可以完全停用压缩,也可以重建压缩表。禁用它可以使用

Gc.set { Gc.get () with Gc.max_overhead = max_int }

检测是否发生了压缩可以通过在每次访问表时比较返回的数字来完成

( Gc.quick_stat () ).Gc.compactions

请注意,在访问表之前,必须禁用压缩。 如果禁用压缩,则还应考虑更改分配策略以避免堆的无限碎片。

Gc.set {(Gc.get ()) with Gc.allocation_policy = 1}

如果你想要在旧版本的OCaml(4.00之前)中有一些非常丑陋的东西,压缩会在内存中保持相同的顺序,所以你可以基于物理地址实现一个集合或映射,而不必担心。

最新更新