什么是“固定一切”设计模式?


74

Stephendevgins在linuxdevcenter.com上的2003年这篇文章中,Bram Cohen的BitTorrent被描述为使用了“修复一切”设计模式。

Cohen使用幂等性是一种较不常见的方法,这两种方法都使BitTorrent较难掌握,但值得研究。多次应用一个过程是幂等的,不会导致任何进一步的更改。科恩说,他使用一种称为“固定一切”的设计模式,该功能可以对许多更改做出反应,而无需真正注意所有更改。他解释说:“您注意到发生的事件,然后调用以这种完全幂等的方式编写的fix all函数,然后清除可能发生的一切并从头开始重新计算。” 幂等使某些困难的计算变得容易,但使事情有些混乱。通话发生什么变化并不总是很清楚,如果有的话。您不需要事先知道。您可以自由调用该函数,

听起来很不错。

但是,在我看来,调用幂等“修复所有问题”功能将以提高效率为代价提高系统的鲁棒性,并有可能搞砸包含系统(可能更喜欢仔细计划和执行的过程)。

不过,我不能说我曾经使用过它。我也无法在线找到他的应用程序的来源(但是我确实找到了一个声称基于它的应用程序。)。在本文之外也找不到参考(我认为我的google-fu很好),但是我确实在SOApatterns.org上找到了“幂等能力”条目

这个想法被另一个名字更好地了解吗?

什么是“修复一切”设计模式?它的优缺点是什么?


4
我怀疑该名称也是对函数不动点x = f(x)的想法的引用无论将f应用于x多少次,结果都是相同的。获得正确的结果后,重新处理正确的结果将返回相同的正确结果。
9000

7
请注意,任何人都可以给想要的任何名称起任何名字,但这并不能使其成为众所周知的软件模式。幂等性本身就是一个众所周知的概念。看起来好像在这里被创造性地使用了。
罗伯特·哈维

1
这让我想起了如何在Mac OS上实现主事件循环。它是一个对任何事件做出响应的单一函数,通常用于测试所有控件的状态并根据需要更新整个UI。确实,幂等。
卢卡斯

3
This sounds quite nice on the face of it. 真?这对我来说太可怕了!
迈克尔(Michael)

3
@Michael您不喜欢包管理器吗?它们以相同的概念工作,只是规模较小:标记您要系统看起来的样子,运行“修复所有问题”,视情况进行安装/删除/升级,但是只有进行更改时才要做。
伊兹方(Izkata)

Answers:


100

假设您有一个非常复杂的HTML页面-如果在一个下拉列表中选择内容,则可能会出现另一个控件,或者第三个控件中的值可能会更改。有两种方法可以解决此问题:

  1. 为每个控件编写一个单独的处理程序,以响应该控件上的事件,并根据需要更新其他控件。

  2. 编写一个处理程序,查看页面上所有控件的状态,并修复所有问题

第二个调用是“幂等”的,因为您可以一遍又一遍地调用它,并且控件将始终正确排列。然而,如果一个呼叫丢失或重复,例如,如果一个处理程序执行切换,则第一个呼叫可能会出现问题。

第二次调用的逻辑会更加晦涩难懂,但是您只需要编写一个处理程序即可。

而且,您始终可以使用这两种解决方案,并根据需要“为了安全起见”调用“修复所有问题”功能。

当状态可以来自不同的来源时(例如,来自用户的输入还是来自服务器的呈现),第二种方法特别好。在ASP.NET中,该技术与回发的概念很好地结合在一起,因为只要渲染页面,您就只需运行“修复所有功能”。

既然我已经提到事件丢失或重复发生,并且从不同的来源获取状态,我认为很明显,这种方法如何很好地映射到像BitTorrent的问题空间。

缺点?显而易见,缺点是性能受到了影响,因为始终检查所有内容的效率较低。但是像BitTorrent这样的解决方案经过了优化,可以横向扩展,而不是纵向扩展,因此对此类事情非常有用。根据您要解决的问题,它可能不适合您。


9
在我看来,MVC是“修复所有问题”的典型代表:当您修改模型然后从头开始重绘视图时,该视图就被完全重绘,而没有试图弄清楚该动作可能影响了哪些部分。
Matthieu M.

3
这听起来本质上类似于Saltstack,Ansible和Nix等系统背后的原理。在给出配置描述后,理论上您可以将多个不同的系统置于相同的最终状态。
kojiro

1
@MatthieuM。在前端开发中非常流行的React就像是一样,除了它进行虚拟dom差异化,因此它仅通过实际更改来更新真实dom
Izkata 2015年

2
@Izkata除了响应之外,这个答案让我想到了Redux。
凯文

2
可能需要指出“修复所有问题”和幂等是不同的东西:“修复所有问题”通常是幂等的(但不是必须的),幂等运算不需要修复所有问题甚至不需要性能。惩罚-两次执行时只给出相同的结果。
汉斯·彼得·斯特尔

15

我认为这篇文章有些过时,因为在我阅读本文时,这根本不是一个非传统的想法或新想法。当它实际上只是一个简单的Observer实现时,将其作为单独的模式呈现。回想我当时的工作,我记得在逻辑上做一些事情,使之坐在一个稍微复杂的界面后面,该界面具有许多相互依赖的数据。用户可以更改值和/或运行优化例程,并基于这些操作生成事件,UI将根据需要监听和更新这些事件。在开发过程中存在许多问题,某些面板无法按时更新。解决方法(保留在设计中)是从其他事件生成事件。最终,当一切正常时,几乎所有更改都会刷新所有面板。试图隔离给定的面板何时需要刷新的所有复杂性都没有了。无论如何都没关系。实际上,这是一个过早的优化。通过将全部折叠为一个刷新所有事件的事件,我将节省大量时间和精力。

“修复所有内容”或刷新所有内容的方式设计了无数系统。考虑所有添加/更新行然后重新查询数据库的CRUD接口。这不是一种奇特的方法,它只是显而易见的非明智的解决方案。您必须意识到,在2003年,正是“模式热”的高峰。据我所知,人们认为命名新模式将成为他们成名和致富的道路。别误会,我认为模式的概念对于抽象描述解决方案非常有用。事情有点偏离轨道了。不幸的是,因为它在总体上引起了人们对模式概念的冷嘲热讽。仅在这种情况下才有必要将其称为“非正统”解决方案。它' 类似于ORM或DI容器周围的正统观念。即使人们早在使用这些工具之前就已经在构建软件,而且在许多情况下这些工具已经过时,否则不使用它们被认为是不合常规的。

回到“修复所有问题”。一个简单的例子是计算工具。简单的解决方案是对数字求和,然后除以值的基数。如果添加或修改数字,则只需从头开始再次进行。您可以跟踪总和和数字计数,当有人添加数字时,您可以增加计数并将其添加到总和中。现在,您无需再次添加所有数字。如果您曾经使用过带有引用范围的公式并修改了该范围内的单个值的Excel,则有一个“固定所有内容”模式的示例,即,任何引用该范围的公式都将重新计算该值是相关的(例如,使用类似sumif()的东西)。

这并不是说在给定的上下文中这不是明智的选择。在平均示例中,可以说我们现在需要支持更新。现在,我需要以某种方式知道旧值,并且仅将增量更改增量。在您考虑尝试在分布式或并发环境中进行此操作之前,所有这些都不是真正的挑战。现在,您必须处理各种棘手的计时问题,并且最终可能会造成一个主要瓶颈,这不仅使速度减慢,还比重新计算要慢得多。

结果是“修复所有问题”或“刷新所有问题”方法更容易正确。您可以使更复杂的方法起作用,但是它要复杂得多,因此更有可能出现缺陷。此外,在许多情况下,“刷新一切”方法可能更有效。例如,对于单线程方法,写时复制方法通常较慢,但是当您具有较高的并发性时,它可以避免锁,从而提供更好的性能。在其他情况下,它可以使您以有效的方式将更改一起批处理。因此,对于大多数问题,除非您有无法执行此操作的特定原因,然后可能会担心需要做一些更复杂的事情,否则,您可能要从“刷新所有内容”方法开始。


2
我很确定Excel仅打算重新计算依赖于更改的单元格,这就是为什么存在一种触发所有单元格重新计算的方式的原因:superuser.com/questions/448376/…(我想这将是“修复所有问题”) )
亚伦·霍尔

@AaronHall如果这样做,那将是一个非常糟糕的实现。我经常观察它在15-30分钟内消耗7个CPU的100%计算例如60,000个单元。计算并不复杂。我经常编写Python程序,可以在几秒钟内完成工作表中的所有功能,包括启动Python。这是我可能要花这么长时间的最佳猜测。我想可能是其他事情。Excel中还存在许多非常老的错误,这可能是该功能的原因。
JimmyJames

1
@AaronHall也可能与该用户一起在工作表上禁用自动计算。我经常在大型工作簿上执行此操作,因为每次按下Enter键时我都没有15分钟的空闲时间。
JimmyJames

@AaronHall我想了一点,你有意思。我的假设可能过于宽泛。我更新了对我的答案,重点更多地放在了我更自信的事情上
。– JimmyJames

2
@JimmyJames:我的意思是,最佳方法可能会根据情况而有很大不同,并且“修复所有问题”可以细分为“在每个单独的更改中紧急修复所有问题”和“在所有更改完成后延迟修复所有问题” ”。
超级猫

4

不确定这是“设计模式”,但我会将该行为类型归类为Puppet,Chef或Powershell DSC的最终状态配置所需状态配置

这些解决方案通常在系统管理级别上运行,而不是问题所描述的业务逻辑级别上运行,但实际上是相同的范例,尽管此类工具本质上通常是声明性的,但是相同的原理也可以应用于过程代码或脚本中。


1

我主要在用户界面中使用此功能。令人高兴的是,您只需编写一次,它就可以很好地处理从最简单到最困难的所有情况(例如,如果用户旋转屏幕,或者如果用户调整窗口大小,则在笔记本电脑/台式机上,几乎所有内容都会改变) )。

没有太多理由担心效率。在用户界面中,昂贵的事情是诸如重新绘制已移动的项目之类的事情。通常计算每个项目的去向和大小是非常快的。您需要确保的是,只要发现某个项目应该确切地停留在其所属位置,就不会执行任何代码来移动它。真正的改变是您无论如何都要做的所有事情。


0

听起来像反应式编程原理。“修复所有问题”着眼于当前的“核心”状态,并传播应该受到影响的其他所有内容-“计算状态”。如果您优化此推导,它可能会达到很高的效率,即使是天真地做,a-la React的性能也可能不是最佳的,尽管它仍然足够快。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.