如何处理这两个相互依赖的信号?
Posted
技术标签:
【中文标题】如何处理这两个相互依赖的信号?【英文标题】:How to handle the two signals depending on each other? 【发布时间】:2014-02-18 13:09:24 【问题描述】:我阅读了Deprecating the Observer Pattern with Scala.React,发现反应式编程非常有趣。
但有一点我想不通:作者将信号描述为 DAG(有向无环图)中的节点。那么如果你有两个相互依赖的信号(或事件源,或模型,w/e)怎么办?即“双向绑定”,例如 Web 前端编程中的模型和视图。
有时这是不可避免的,因为用户可以更改视图,而后端(例如异步请求)可以更改模型,您希望对方立即反映更改。
【问题讨论】:
您的问题是针对 scala.react 的吗?最后我记得它不是那么有用 @dcsbral / OP 你能澄清一下吗? @nafg 你拼错了我的昵称,所以我没有看到你的评论。我希望这个问题确实是针对 scala.react 的。尽管我希望您能就您自己的框架如何处理它提出意见。 我不得不说,我对答案真的很失望。他们似乎都去谈论其他人如何在其他 FRP 软件中解决它,或者告诉您去阅读其他人的论文,其中讨论了该主题并从中得出自己的答案。 Stack Overflow 的答案不应该是这样。我将赏金授予唯一真正谈到解决方案的答案,尽管它(答案)是一种逃避。 @DanielC.Sobral - 对此感到抱歉。在反应式中(至少目前)并不难,因为它不是基于显式图。你可以更新例如信号所依赖的 Var。还有 .distinct 和 .nonrecursive 可以防止无限循环。将来虽然 G-d 愿意,但我希望有一种基于图形的方法来使用它。 【参考方案1】:检查您的MVC 知识。视图不会更新模型,因此它不会向它发送信号。控制器更新模型。对于 C/F 转换器,您将有两个控制器(一个用于 F 控制,一个用于 C 控制)。两个控制器都会向单个模型发送信号(该模型将唯一的真实温度 Kelvin 存储在 lossless format 中)。该模型将信号发送到两个单独的视图(一个用于 C 视图,一个用于 F 视图)。没有循环。
根据@pagoda_5b 的回答,我想说你可能允许有循环(7.6 应该处理它,但要以性能为代价),但你必须保证没有无限倒退。例如,您可以让控制器也接收来自模型的信号,只要您保证接收到所述信号不会导致信号被发送回模型。
我认为上面的描述很好,但是它在非FRP样式中使用了“信号”一词。上面的“信号”实际上是消息。如果 7.1 中的描述正确且完整,则信号图中的循环将始终导致无限回归,因为处理节点的依赖项会导致节点被处理,反之亦然,ad inf。
正如@Matt Carkci 所说,有一些 FRP 框架允许循环,至少在有限的范围内。它们要么不是基于推送的,以有趣的方式使用非严格性,强制单调性,要么引入“人为”延迟,以便当信号图在时间维度上扩展(将其转换为值图)时,循环消失。
【讨论】:
【参考方案2】:扫描纸张后,我找不到他们提到它必须是非循环的。没有什么能阻止您在数据流/反应式编程中创建循环图。非循环图只允许您创建管道数据流(例如 Unix 命令行管道)。
反馈和循环是数据流中非常强大的机制。没有它们,您将受限于可以创建的程序类型。看看Flow-Based Programming - Loop-Type Networks。
在pagoda_5b
第二次发帖后编辑
报纸上的一句话让我注意到了……
对于正确排序的图,这个过程 单调地前进到更高的水平,从而确保数据 一致性,即没有故障。
对我来说,Scala.React 框架中不允许循环。两个节点之间的循环似乎会导致系统不断尝试永远提高两个节点的级别。
但这并不意味着您必须在其框架内对循环进行编码。可能有一个从您要观察的项目开始的路径,然后是另一个单独的返回 GUI 的路径。
对我来说,似乎总是过于强调编程系统完成并给出一个答案。循环使得很难确定何时终止。使用“反应式”一词的图书馆倾向于认同这种思维过程。但这只是冯·诺依曼计算机体系结构的结果……解决方程并返回答案的重点。回避循环的库似乎担心程序终止。
Dataflow 不需要程序有一个正确答案或永远终止。由于此时的输入,答案是此时的答案。如果不需要,则需要反馈和循环。数据流系统基本上只是一个在节点之间不断传递数据的大循环。要终止它,您只需停止它。
数据流不必那么复杂。这只是一种非常不同的编程方式。我建议您查看 J. Paul Morison 的书 "Flow Based Programming" 以了解数据流的现场测试版本或 my book(一旦完成)。
【讨论】:
【参考方案3】:反应式编程语言中的循环依赖可以用多种语义来处理。在 scala.React 中似乎选择了一种同步反应式语言,特别是 Esterel。您可以在 Benveniste, A 的论文“12 年后的同步语言”中很好地解释这种语义及其替代方案。卡斯皮,P。爱德华兹,S.A.;哈布瓦克斯,N。勒格尔尼克,P。 de Simone, R. 和 http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=1173191&tag=1 或 http://virtualhost.cs.columbia.edu/~sedwards/papers/benveniste2003synchronous.pdf 联系。
【讨论】:
【参考方案4】:在这里回复@Matt Carkci,因为评论不够用
在论文部分 7.1 Change Propagation 你有
我们的变更传播实现使用基于拓扑有序依赖图的基于推送的方法。当一个传播回合开始时,传播者将自上次回合以来失效的所有节点放入一个优先级队列,该队列根据拓扑顺序,简要级别排序,节点。传播者将最低级别的节点出列并验证它,可能会更改其状态并将其更高级别的依赖节点放入队列中。传播者重复此步骤,直到队列为空,始终跟踪当前级别,这对于下面的级别不匹配变得很重要。对于正确排序的图,这个过程单调地进行到更高的级别,从而确保数据的一致性,即没有毛刺。
7.6 级别不匹配
节之后因此我们需要准备一个不透明的节点n来访问另一个更高拓扑级别的节点。在 n 评估期间读取的每个节点,首先检查传播者维护的当前传播级别是否大于节点的级别。如果是,它照常进行,否则它抛出一个包含对自身的引用的级别不匹配异常,该异常仅在主传播循环中被捕获。然后传播者提升 n,首先将其级别更改为引发异常的节点上方的级别,然后将 n 重新插入传播队列(因为它的级别已更改)以备后用在同一轮中进行评估,然后传递提升所有 n 的依赖项。
虽然没有提及任何拓扑约束(循环与非循环),但仍有一些不清楚的地方。 (至少对我来说)
首先出现的问题是如何定义拓扑顺序。
然后实现表明,相互依赖的节点将通过上面解释的异常机制在评估中永远循环。
你怎么看?
【讨论】:
en.wikipedia.org/wiki/Topological_sorting -- "当且仅当图没有有向环,即,如果它是有向无环图 (DAG),拓扑排序是可能的。"以上是关于如何处理这两个相互依赖的信号?的主要内容,如果未能解决你的问题,请参考以下文章