我希望保持各种数据源同步。为此,我想使用事件中心广播更改事件。因此,在此结构中,每个数据源都可以是发布者和事件的订阅者。目前我还没有实现,我只想着如何做到这一点。
我有问题弄清楚如何防止事件反射(其他术语中的无限循环)。所以通过数据源
-> ds.change -> hub.publish(ds, event) -> hub.subscriber[x] = ds.sync(event)
-> ds.change -> ... //infinite loop caused by sync triggered change event
这是一个基本的反映(在我看来),这可以通过简单地忽略来自集线器上相同ds(数据源)的相同事件来避免,直到完成当前事件处理过程。但我们怎么知道什么时候完成呢?
通过同步代码,我们可以简单地用事务覆盖进程,并检查当前ds是否已经同步。如果是,则忽略它。如果我们有2个集线器同步相同的2个数据源怎么办:
-> ds.change -> hub1.publish(ds, event) -> hub.subscriber[x] = ds2.sync(event)
-> ds2.change -> hub2.publish(ds2, event2) -> hub2.subscriber[x] = ds.sync(event2)
-> ds.change -> ... //infinite loop caused by signal sent back by the other hub
因此我们必须使用相同的交易来覆盖2个集线器。所以我们必须使用某种全局交易。
现在所有这些都可以通过同步代码或多或少地解决。但是异步代码怎么样?如果我无法准确确定何时应该这样做,我该如何结束交易呢?过早或过晚结束交易会导致申请状态无效。向事件添加事务ID并永不结束事务将导致内存泄漏。有什么想法吗?
问题的异步部分非常困难,更多的是并发线程,线程安全和并行编程,然后是简单的事件处理。所以我决定接受T.J. Crowder的答案,因为比较值而不是创建全局事务对象是一个天才的想法。如果您对问题的异步部分有一般解决方案,请与我们分享!
我在这里问了同样的问题:https://softwareengineering.stackexchange.com/questions/241599/how-to-avoid-oscillation-by-async-event-based-systems我得到了一个关于如何防止状态振荡的更一般的答案。
答案 0 :(得分:3)
如果发布商仅在更改时引发事件,则您将避免无限循环如果可以保证订阅者在接收以后的事件之前接收先前的事件。您可以通过同步或异步事件调度来确保保证;在后一种情况下,这是更多的工作,因为订阅者必须承认在你给他们下一个事件之前收到了一个事件。基本上,订户需要有待处理事件的FIFO队列。
假设A
订阅了来自x
的{{1}}的更改事件,并且B
订阅了来自B
的{{1}}更改事件。然后更改x
:
A
看到A.x
值已更改,保存新值并提出更改。A
会看到来自x
的事件,将事件的B
与自己的事件进行比较,看到它们不同,保存并提出更改。A
从x
看到更改事件,将事件的A
与自己的事件进行比较,看到它们是相同的,并且没有做任何事情。如果您无法获得该保证,那么您会遇到下面描述的问题:B
可能会引发将x
更改为A
的事件,然后引发另一项更改{ {1}}到x
,如果1
在x
更改之前看到2
更改,则B
和x=>2
可能会结束在一个永无止境的循环中。