是否可以有效地表示具有不变状态的对象图的突变?


12

我正在练习在C ++中使用不可变对象。我的个人目标是用不可变图序列表示通用对象图(在堆中)。

构建多版本图本身并不难。问题是性能。蛮力版本控制需要图形的完整副本,这是不可接受的。

我试图共享不变的节点。但是在这种情况下,我遇到了一个新问题。参考。对其他对象的引用必须在整个图中进行更新。每次派生新图版本时,都需要访问所有节点。并且这会使带有引用的节点发生变异,因此也应该派生它们(通过复制)。性能不会比暴力复制更好。

据我所能想象,没有真正有效的方法来表示具有不变状态的对象图的突变。因此,我希望对此有所想法。

是否可以用不变状态有效地表示对象图的变化?


1
这只是困难的,因为您要在节点上放置边缘。如果将边缘存储在一个不可变的集合中,这将很容易。
dan_waterworth

@dan_waterworth如果使用邻接表,则必须每次搜索每个边缘。因此,我认为这是读写性能之间的权衡。
Eonil

1
它不必是列表。
dan_waterworth

@dan_waterworth你的意思是像B树吗?
Eonil

2
当对存储介质的等待时间较高时,倾向于使用像B树这样的宽树。在这种情况下,最好使用较窄的东西,但是是的,某种平衡的搜索树将是一个好主意。
dan_waterworth

Answers:


11

您要查找的内容称为持久数据结构。持久性数据结构的规范资源是克里斯·冈崎(Chris Okasaki)的《纯功能数据结构》。由于持久数据结构在Clojure和Scala中的普及,最近引起了人们的关注。

但是,由于某些奇怪的原因,似乎几乎忽略了持久图。我们有列表,数十种不同种类的树,数组,优先级队列,地图,但没有图。

我真的只发​​现了一篇论文:完全持久图–选择哪一个?


4

如果您不认为对象之间的连接是版本化资源的一部分(并且您可能会遇到这种情况(在这种情况下,可能没有多大帮助)),则可以考虑将对象拆分为代表连接部分的一部分对象和代表不可变状态的部分。

然后,您可以使每个连接子对象都包含版本化状态的向量。这样,您可以使用图形版本号进行操作以访问适当的不可变状态。

为了避免每次对特定节点进行更新时都必须遍历整个图,您可以进行修改,以便如果访问的节点的版本号大于该节点的当前版本号,则使用当前版本。如果随后更新了该节点,则可以使用先前的版本填充所有中间版本,从而可以对对象图进行延迟更新。

如果对象之间的连通性是版本状态的一部分,则前述内容不起作用。但也许您可以将其扩展如下:

对于图中的每个对象,创建一个“句柄对象”。句柄对象包含版本化不可变状态的列表。与其将对象引用存储在图形的任何对象中,不如存储对句柄对象的引用。然后,将使用句柄和当前正在处理的对象图的视图的版本号通过句柄来取消对对象的每个引用。这将为对象返回正确的不可变状态。不可变状态使用句柄引用图形中的其他对象,因此您始终会获得要处理的图形版本的一致日期。

上面描述的相同逻辑适用于更新句柄中的版本-允许进行延迟的本地化更新。


3

有一个已发布的解决方案,具有很好的摊销时间复杂度,但是当您不知道要查找的内容时很难找到它。您可以在这些讲义中找到不错的摘要(请参阅第2.2.3节),或阅读原始论文《使数据结构持久化》。如果对象图的连接性有限(例如,树状结构),则即使读取和更新不可变图,您甚至可以达到摊销O(1)的复杂性,这令人印象深刻。

这个想法是,每个对象除了存储其当前的不可变状态外,还保留用于记录更改的空间。当您想通过应用更改从现有图形创建新的不可变图形时,必须考虑两种情况:

  • 您要更改的对象仍有更改空间。您可以将更改直接存储在对象中。

  • 该对象没有更多更改空间。您基于当前值创建新实例,并清空更改记录。现在,您需要递归更新所有引用旧对象的对象,以引用新对象。

    如果引用对象本身仍有更改空间,则可以将更改直接存储在引用中,否则它将以递归方式级联。

尽管此方案支持高效创建新一代的不可变对象图,但使读取它变得复杂,因为现在您需要指定从不可变对象读取数据时要访问的“版本”。这是因为由于存储的更改记录,不可变对象可能具有多个版本的信息,因此您需要指定要查看的版本。

在实现这一点时,我尝试在API中隐藏这种复杂性。当从外部引用不可变图中的某些内容时,我使用生成的存根而不是直接引用,因此调用者不需要一直手动传递所需的版本。这使引用比直接指针要贵一些,但是我发现值得这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.