What is differential execution?
我偶然发现了一个堆栈溢出问题,差分执行是如何工作的?这是一个非常详细的答案。所有这些都很有意义…但当我完成后,我仍然不知道究竟是什么样的差分执行。真的是什么?
修订过的。这是我第n次试图解释它。好的。
假设您有一个简单的确定性过程,它重复执行,总是遵循相同的语句执行顺序或过程调用。该过程调用自己按顺序将所需的内容写入FIFO,并从FIFO的另一端读取相同数量的字节,如下所示:**好的。
好的。
正在调用的过程使用FIFO作为内存,因为它们读取的内容与在先前执行时写入的内容相同。所以,如果这次他们的论点与上次恰好不同,他们可以看到这一点,并用这些信息做任何他们想做的事情。好的。
要启动它,必须有一个初始执行,其中只进行写入,不进行读取。在对称的情况下,应该有一个最终的执行,其中只进行读取,而不进行写入。所以有一个"全局"模式寄存器包含两个位,一个允许读取,另一个允许写入,如下所示:好的。
好的。
初始执行是在模式01中完成的,因此只完成写入。过程调用可以看到模式,因此它们知道没有以前的历史记录。如果他们想创建对象,他们可以,并把识别信息放在FIFO中(不需要存储在变量中)。好的。
中间执行是在模式11下完成的,因此读写都会发生,过程调用可以检测数据更改。如果有需要更新的对象,它们的识别信息是从FIFO读取并写入的,因此可以访问它们,并在必要时进行修改。好的。
最后一次执行是在模式10中完成的,因此只进行读取。在这种模式下,过程调用知道它们只是在清理。如果维护了任何对象,则从FIFO读取它们的标识符,并且可以删除它们。好的。
但真正的程序并不总是遵循相同的顺序。它们包含if语句(以及改变它们所做操作的其他方法)。如何处理?好的。
答案是一种特殊的if语句(及其终止endif语句)。这就是它的工作原理。它写入其测试表达式的布尔值,并读取上次测试表达式的值。这样,它就可以判断测试表达式是否发生了更改,并采取行动。它所采取的行动是暂时改变模式寄存器。好的。
好的。型
具体来说,x是测试表达式的先前值,从FIFO读取(如果启用了读取,则为0),y是测试表达式的当前值,写入FIFO(如果启用了写入)。(实际上,如果未启用写入,则不会计算测试表达式,y为0。)然后x,y简单地屏蔽模式寄存器r,w。因此,如果测试表达式从true更改为false,那么主体将以只读模式执行。相反,如果它已从false更改为true,则主体将以只写模式执行。如果结果为00,则跳过if..endif语句中的代码。(您可能会想一想,这是否涵盖了所有的情况——确实如此。)好的。型
它可能并不明显,但这些if..endif语句可以任意嵌套,并且可以扩展到所有其他类型的条件语句,如else、switch、while、for,甚至调用基于指针的函数。在这种情况下,只要遵循模式,过程就可以在任何程度上被划分为子过程,包括递归过程。好的。型
(必须遵循一条规则,称为擦除模式规则,即在模式10中,不应计算任何结果,如跟踪指针或索引数组。从概念上讲,原因是模式10的存在只是为了摆脱一些东西。)好的。型
因此,它是一个有趣的控制结构,可以用来检测变化,通常是数据变化,并对这些变化采取行动。好的。型
它在图形用户界面中的用途是使一些控件或其他对象与程序状态信息保持一致。为此,三种模式分别称为显示(01)、更新(11)和擦除(10)。该过程最初以显示模式执行,在该模式下创建控件,与这些控件相关的信息填充FIFO。然后在更新模式下执行任意数量的操作,在更新模式下,根据需要修改控件,以保持程序状态的最新。最后,在擦除模式下执行,在这种模式下,控件从UI中移除,FIFO被清空。好的。型
。好的。型
这样做的好处是,一旦您编写了创建所有控件的过程,作为程序状态的一个函数,您就不必编写任何其他内容来保持程序的更新或清除。任何你不需要写的东西都意味着更少的犯错机会。(有一种简单的方法可以处理用户输入事件,而不必编写事件处理程序并为其创建名称。这在下面链接的一个视频中解释。)好的。
在内存管理方面,不需要组成变量名或数据结构来保存控件。它在任何时候都只为当前可见的控件使用足够的存储空间,而潜在可见的控件可以是无限的。此外,以前使用过的控件的垃圾收集也不存在任何问题——FIFO充当自动垃圾收集器。好的。
在性能方面,当它创建、删除或修改控件时,无论如何都需要花费时间。当它只是更新控件而没有更改时,与更改控件相比,读取、写入和比较所需的循环是微观的。好的。
另一个性能和正确性方面的考虑是,相对于为响应事件而更新显示的系统,这样的系统要求对每个事件都做出响应,而不响应两次,否则显示将不正确,即使某些事件序列可能是自取消的。在差分执行下,可以根据需要尽可能频繁或尽可能少地执行更新传递,并且在传递结束时显示总是正确的。好的。
这里有一个非常简单的例子,其中有4个按钮,其中按钮2和3是以布尔变量为条件的。好的。
(在本例中,更改按与所做更改相反的顺序撤消,但这不是必需的。可以按任意顺序进行更改和取消编码。)好的。
请注意,在任何时候,由新旧连接在一起的FIFO都包含可见按钮的参数和布尔值。好的。
这一点是为了展示一个单独的"画图"程序是如何在不改变的情况下用于任意的自动增量更新和擦除的。我希望很明显,它适用于任意深度的子过程调用和任意条件嵌套,包括
好的。
最后,这里还发布了一些粗俗但简短的视频。好的。
**从技术上讲,它们必须读取上次写入的相同字节数。例如,他们可能写了一个前面有字符计数的字符串,这没关系。好的。
他补充说:"我花了很长时间才确定这项工作是否会一直有效。我终于证明了这一点。它基于一个同步属性,大致意味着在程序的任何一点上,在前一个过程中写入的字节数等于在后一个过程中读取的字节数。证明背后的想法是通过对程序长度的归纳来实现。要证明的最困难的情况是,程序的一部分由s1和if(test)s2 endif组成,其中s1和s2是程序的子部分,每个子部分都满足sync属性。只在文本中做这件事是装玻璃的,但在这里我试着用图表说明它:好的。
它定义了sync属性,并显示代码中每一点写入和读取的字节数,并显示它们是相等的。关键点是:1)当前过程中读取的测试表达式(0或1)的值必须等于先前过程中写入的值;2)满足同步条件(s2)。这满足组合程序的同步属性。好的。好啊。
我读了所有我能找到的东西,看了视频,并将在第一原则描述拍摄。好的。
概述好的。
这是一种基于DSL的设计模式,用于以一种干净、高效的方式实现用户界面,或者其他面向状态的子系统。它着重于改变GUI配置以匹配当前程序状态的问题,其中该状态包括GUI小部件本身的条件,例如用户选择选项卡、单选按钮和菜单项,小部件以任意复杂的方式出现/消失。好的。
描述好的。
模式假定:好的。
- 添加一个p-用参数p将一个新对象a放入c。
- 修改P—将C中对象A的参数更改为P。
- 删除A-从C中删除对象A。
- 使用可选提示h创建一个h-实例化某个对象a,并将其添加到全局状态。(注意此处没有参数。)
- 如果b,那么t else f—根据布尔函数b有条件地执行命令序列t或f,布尔函数b可以依赖于正在运行的程序中的任何内容。
在所有的例子中,好的。
- 全局状态是一个GUI屏幕或窗口。
- 这些对象是UI小部件。类型包括按钮、下拉框、文本字段…
- 参数控制小部件的外观和行为。
- 每次更新都包括在GUI中添加、删除和修改(例如重新定位)任意数量的小部件。
- 创建命令正在生成小部件:按钮、下拉框…
- 布尔函数依赖于底层程序状态,包括GUI控制本身的条件。因此更改控件会影响屏幕。
缺少链接好的。
发明家从来没有明确地声明过它,但一个关键的想法是,我们在程序上运行DSL解释器,每当我们期望布尔函数值b的任何组合发生更改时,该解释器表示所有可能的目标集合(屏幕)。解释器通过发出一系列的添加、删除和修改操作来处理使集合(屏幕)与新的b值一致的脏工作。好的。
最后还有一个隐藏的假设:DSL解释器包含一些算法,可以根据当前运行期间迄今为止执行的创建历史为添加和修改操作提供参数。在GUI上下文中,这是布局算法,创建提示是布局提示。好的。
Punch Line喜剧俱乐部好的。
该技术的强大之处在于将复杂性封装到DSL解释器中的方式。一个愚蠢的解释器将从删除集合(屏幕)中的所有对象(小部件)开始,然后为每个创建命令添加一个新的对象,就像它在单步执行DSL程序时看到的那样。修改永远不会发生。好的。
差分执行对于解释器来说只是一种更聪明的策略。它相当于保存解释器最后一次执行的序列化记录。这是有意义的,因为录制会捕获屏幕上当前的内容。在当前运行期间,解释器查询记录,以决定如何使用成本最低的操作来实现目标集合(小部件配置)。这意味着永远不会删除一个对象(小部件),只会在以后以2的成本再次添加它。DE将始终修改,其成本为1。如果我们碰巧在某些情况下运行解释器,而b值没有改变,那么de算法将根本不会生成任何操作:记录的流已经代表了目标。好的。
当解释器执行命令时,它也在为下一次运行设置记录。好的。
类似的算法好的。
该算法与最小编辑距离(med)具有相同的风格。但是,反序列化是一个比med更简单的问题,因为反序列化执行字符串中没有med中的"重复字符"。这意味着我们可以用一个简单的在线贪婪算法而不是动态规划找到一个最优解。这就是发明者的算法所做的。好的。
优势好的。
我的看法是,这是一个很好的模式,用于实现具有许多复杂形式的系统,在这些形式中,您希望通过自己的布局算法和/或可见内容的"if-else"逻辑对小部件的放置进行完全控制,并且这种逻辑被深度嵌套。如果在表单逻辑中有k个"if elses"n的嵌套,那么就有k*2^n个不同的布局来实现正确的布局。传统的表单设计系统(至少是我使用过的系统)根本不支持更大的k,n值。你往往会以大量相似的布局和特殊的逻辑结束,选择那些丑陋且难以维护的布局。这种DSL模式似乎是一种避免这一切的方法。在具有足够形式来抵消DSL解释器成本的系统中,在初始实现期间甚至会更便宜。关注的分离也是一种力量。DSL程序抽象表单的内容,而解释器是布局策略,根据来自DSL的提示进行操作。获得DSL和布局提示设计的正确性本身似乎是一个重要而酷的问题。好的。
可疑的…好的。
我不确定在现代系统中,避免删除/添加对而支持修改是否值得所有麻烦。发明家似乎对此优化最为自豪,但更重要的想法是使用条件来表示形式的简洁DSL,在DSL解释器中隔离布局复杂性。好的。
扼要重述好的。
到目前为止,这位发明家一直专注于口译员如何做出决定的深入细节。这是令人困惑的,因为它是针对树木的,而森林更感兴趣。这是森林的描述。好的。好啊。