【问题标题】:Event driven architecture...infinite loop事件驱动架构...无限循环
【发布时间】:2011-04-10 22:16:45
【问题描述】:

我有一个事件驱动架构,其中 A 等待 B 的更改,B 等待 C 的更改,C 等待 A 的更改,形成一个循环。

现在,如果 B 发生变化,则 A 向 C 触发一个事件,C 向 B 触发,B 向 B 触发,A 向 C 触发……无限。

我现在可以更改我的程序以不包含此循环,但我担心我可能会在以后将自己置于无法控制的角落。在设计基于事件的系统时如何防止此类事情发生?

【问题讨论】:

  • 听起来像递归......你需要一个保护子句/基本案例来停止事件。
  • 有趣,我也遇到了同样的事情。最后,我们不得不重构整个代码部分。
  • 这听起来像是应用finite state machine 的完美场景。

标签: events architecture event-driven-design


【解决方案1】:

这里的每个人似乎都说循环依赖是不好的。这在某种意义上是正确的,我几乎不惜一切代价避免静态循环依赖。您可以通过以下博客中所述的控制反转来做到这一点:http://blog.schauderhaft.de/2011/07/17/breaking-dependency-cylces/

但是您所描述的不一定是静态循环依赖,而是运行时的依赖。我不完全确定,但我认为在运行时避免循环依赖或多或少是不可能的。但是当然这不应该导致无限循环。为了解决这些问题,我看到了两个半选项

首先是破解

确保由另一个事件触发的每个事件都具有对原始事件的引用(或关于它的基本信息,如 id)。当你处理一个事件时,请确保它不是来自你自己。

专业版:易于实施;绝对防止递归

破解的另一半

如果您正在同步运行,您可以在之前设置标志 firingEvent 并在之后重置它。在设置 firingEvent 时忽略传入的事件。

Pro:更容易实现;在单线程中运行时绝对防止递归

语义丰富的解决方案

我确信 A 在某个外部触发器上触发的事件和 A 因为 C 触发而触发的事件实际上是两个不同的事件,或者所有三个事件实际上只是一个可能来自尚未确定的来源的事件D. 或者类似的东西。没有信息就无法判断 A、B 和 C 是什么以及它们正在触发什么事件。如果你找到合适的事件,循环就会消失。

优点:设计会更简洁,包含更多信息。

【讨论】:

    【解决方案2】:

    列出你的依赖关系。不应该有循环。循环依赖是重组代码的好借口。

    它们也可能导致死锁,以防您需要其他理由来避免它们。

    【讨论】:

    • 是的,但是如果您的事件驱动系统不包含在单个服务中怎么办。例如,如果您正在运行一个微服务架构,其中每个服务都拥有自己的数据,并且您正在利用事件溯源来保持上下文/服务之间的相关数据同步。您不一定知道可能导致循环的处理程序的每种组合 D:
    【解决方案3】:

    在设计基于事件的系统时如何防止此类事情发生?

    1. 仅在对象状态真正改变时引发事件。

    2. 禁止在引发事件时更改对象状态。

    【讨论】:

      【解决方案4】:

      我认为这是一个很好的问题。不幸的是,我自己没有完整的答案,但这篇文章有几个优点:

      how to avoid infinite loop in observer pattern?

      我不认为答案是避免循环依赖,正如其他人所建议的那样。 (嗯,这取决于你对“循环依赖”的定义。)像 Java 这样的语言将在编译时使用接口来最小化类型的循环依赖,这通常是一个好主意。例如,MVC 模式中的视图类不“依赖”您的应用程序,它只知道名称为 ValueChangedListenerClickListener 等的接口。但这并不能消除运行时对象之间的循环连接时间,这会导致事件循环。

      正如在其他链接帖子中提到的,UI 工具包中的某些循环会停止,因为如果控制器或模型将视图的值“设置”为等于其当前值的值,则视图不会触发“更改”事件。但在其他情况下,例如当您为更复杂的数据创建自定义视图时,计算当前数据和新数据的相等性可能是不可行的。

      【讨论】:

        【解决方案5】:

        循环依赖真的很糟糕。在我理解之前,我不得不用 A、B 和 C 的形式写下你的帖子。我认为你应该摆脱它。如果你把自己置于一个角落,它可能比你可能遇到的循环依赖问题要好得多。

        您当然也可以避免这种情况。 A、B 和 C 确实是紧密耦合的。我认为你需要重新考虑他们的责任。也许有一个常见的 D 元素可以减轻您的设计压力。

        想到的其他东西是architectural Layering。如果您可以将 A 置于 B 之上,并要求与 B 交谈的任何人进行沟通以通过 A 并向下层,那么您可能会给自己一个更轻松的时间。同样,我对您的问题了解不多,所以这些只是广泛的建议。

        最后一个选项,也是我最不喜欢的,是在三个组件之间传递消息。当每一个被访问时,要求每个组件添加到它已经看到的消息的消息中。然后获取消息的下一个组件包含有关谁看到它的信息。有点像报名表。但同样,最不喜欢的。先试试别的吧。

        祝你好运!

        【讨论】:

        • 我不认为他说的是循环依赖,而是事件循环。 A、B 和 C 正在监听事件,让我们想象代码通过观察者模式完美解耦。问题似乎在于他已经对代码进行了编程,以便一个组件中的更改传播到另一个组件。与代码耦合无关。
        猜你喜欢
        • 2021-12-29
        • 1970-01-01
        • 2014-12-04
        • 2014-01-03
        • 2011-06-17
        • 2015-11-20
        • 2018-11-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多