我正在详细阐述一个对我来说很难的问题,我并不期待一个简单的解决方案,但也许有经过验证的实践或进一步的阅读可能会使这更容易。我很确定许多应用程序中会弹出一般问题(例如垃圾收集或事务数据库)。
我的应用程序有一个图形(如果重要的话,DAG),它同时由多个线程遍历。其中一些只是试图找到某些节点或检索子图,其他可能会改变图的结构。
我想要实现的策略是读取线程将在图形的“快照”上执行其整个操作,即。即看看在某个时间点的结构。
我目前的计划是在事务DB中设置类似于行版本控制的东西,i。即阅读线程首先获取当前版本号,然后仅访问具有此版本号或更早版本的图节点和边。然后,编写线程会在新元素上添加增加的版本号(更改的元素将首先克隆),使其对于运行的读者不可见。写作线程可以在成功完成后“提交”其新版本,读者将“释放”其版本号,使删除的元素有资格删除。
这个策略仍然很粗略,并且有许多未解决的问题,例如并发写访问,但通常它似乎是一条可行的道路。
答案 0 :(得分:4)
替代方案是使用 Persistent Data Structures 。它们是数据结构,在修改时始终保留自身的先前版本。
它们就像一个日志文件,修改后的版本总是最后使它们成为不可变的,因为它们的操作不会(明显地)就地更新结构,而是总是产生一个新的更新结构。编程语言如Clojure lately polularized this approach(至少对我而言)。
答案 1 :(得分:2)
你的方法对我来说似乎很合理......
然而,您可能遇到的问题是确保在不同子图上的写入之间存在因果关系。
如果作者改变子图A而另一个作者改变了不同的子图B,但其他读/写操作发生在子图C上,其中A和B在C中,那么你需要确保子图C的版本与版本正确对齐B和A。
我建议在DAG中使用一个锁定方案,该方案包含子图锁定,用于从给定的根进行多次读/单写。您需要grep图形以获取循环依赖关系,但要确保您不会在图形中进入饥饿/死锁状态。
如果您的图表分布式或您的并发访问权限延迟,那么您的交易系统将更难实施,并且可能需要额外的保护措施。
您的版本控制方法听起来不错,只要您的锁定条款确保在任何时候T节点的一组修订代表图形的整数状态。 T = {n0,n1,n2,n3}处的节点和修订集以及子图的并发修订版本将使整个修订版本和节点保持在T积分时头痛。
作为dfa suggests above,某些节点和修订集代表整个结构的变更集。如果它具有完整性,则表示在某个时间点的整个结构。
记住:时间,完整性,因果关系和并发
祝你好运!
答案 2 :(得分:0)
嗯,我认为我会聪明并且谷歌搜索几个关键词,以找到一些文献。第一个结果......是这个问题。
所以这个话题没有太多内容!有趣。只是想我会分享。
艾登·贝尔和DFA都给出了非常彻底的答案,所以我不会试图超越他们。 :)但我会做一个观察,关于图的DAG质量和并发写访问。这可能已经发生在你身上了,但是嘿。 :)
您可以通过简单地假设在任何时候,写入线程所居住的节点以及该节点的所有子节点都被“锁定”而允许并发线程而不必担心覆盖另一个节点的更改通过特定的写作线程。我发现用树(这显然也是DAG)可视化它是最容易的。任何编写线程基本上都锁定了一个特定的子树,但同样我们现在可以说任何兄弟树或任何祖先节点都是可以写的。
更复杂的DAG(特别是节点可以有多个父节点)实际上会有很多重叠的子树,因此可能没有那么多自由,但规则仍然适用:任何没有居住的节点,或者写入线程所居住的节点的子节点,可以被认为是写入的。
显然,可能有很多因素导致上述想法无效,但如果多个写入线程经常在“不同”方向上停止,则可能会减轻使其成为线程安全所需的一些要求。 / p>
希望这有帮助!
-Agor