Clojure 在并发环境中拍摄复杂可变结构的快照
给定:各种嵌套集合的复杂结构,引用分散在不同级别 需要:一种拍摄此类结构快照的方法,同时允许在其他线程中继续执行写入操作 因此,“读取器”线程需要在单个长事务中读取整个复杂状态。“writer”线程同时在多个短事务中进行修改。据我所知,在这种情况下,STM引擎使用refs历史 这里我们有一些有趣的结果。例如,读卡器在事务开始后10秒内到达某个ref。编写器每1秒修改一次此引用。它产生10个ref历史值。如果超过ref的Clojure 在并发环境中拍摄复杂可变结构的快照,clojure,Clojure,给定:各种嵌套集合的复杂结构,引用分散在不同级别 需要:一种拍摄此类结构快照的方法,同时允许在其他线程中继续执行写入操作 因此,“读取器”线程需要在单个长事务中读取整个复杂状态。“writer”线程同时在多个短事务中进行修改。据我所知,在这种情况下,STM引擎使用refs历史 这里我们有一些有趣的结果。例如,读卡器在事务开始后10秒内到达某个ref。编写器每1秒修改一次此引用。它产生10个ref历史值。如果超过ref的:max history限制,则读卡器事务将永远运行。如果超过:min his
:max history
限制,则读卡器事务将永远运行。如果超过:min history
,事务可能会重新运行多次
但实际上,读者只需要一个ref值(第一个值),而作者只需要一个最近的值。历史记录列表中的所有中间值都是无用的。有没有办法避免这种历史的过度使用
谢谢。您的问题的一般答案是您需要两件事:
- 在Clojure中解决这个问题的惯用方法是将状态放在一个顶级ref中,其中的所有内容都是不可变的。然后,读者可以免费拍摄整个并发状态的快照(甚至不需要事务)。从您当前的位置进行重构可能很困难,但我认为这是最佳实践
- 如果您只希望读取器获取顶级ref的快照,那么您可以直接在事务外部对其进行解引用。请注意,内部的引用可能会继续发生变异,因此这是否有用取决于您对读者的一致性要求
- 您可以在(dosync…)事务中做任何事情,这对于读卡器和写卡器来说都是正常的。您可能会获得争用和事务重试,但这可能不是问题
- 您可以创建一个“快照”函数,该函数可以快速遍历图形并取消引用事务中的所有引用,返回结果时去掉引用(或替换为新的克隆引用)。读取器调用快照一次,然后在快照完成后继续执行其余的工作
- 您可以在编写器每次完成后立即拍摄快照,并将其单独存储在atom中。读者可以直接使用它(即,只有writer线程可以直接访问实时数据图)
然而,快速查看上面的实现应该会让您确信这不是“滚自己的”领域。如果可能的话,我会尝试根据您的需要调整现成的并发数据结构。我链接到的所有内容都可以在JVM上免费获得,但它本身并不是本地Clojure。“奇怪的时间延迟”不是一个有用的问题标题。你们可以把它编辑成一些有用的问题标题。@Lion,我最好重写整个问题,因为有些事情在我重写部分后变得更清楚了