Smalltalk 为什么某些区块关闭优化是好的和有效的?

Smalltalk 为什么某些区块关闭优化是好的和有效的?,smalltalk,Smalltalk,在2001年的一篇非常有趣的文章中,Allen Wirfs Brock解释了如何在不具体化(本机)堆栈的情况下实现块闭包 从他透露的许多想法中,有一个我不太理解,我认为在这里问一下是个好主意。他说: 如果在创建块时将变量的副本放置在闭包中,则在块的生命周期内永远无法分配的任何变量(例如,封闭方法和块的参数)无需放置在环境中 有两件事我不太清楚: 为什么使用只读变量的两个副本比将变量移动到环境中要快?是因为封闭上下文访问堆栈中的(原始)变量会更快吗 我们如何确保这两个变量保持同步 问题1肯定还有另

在2001年的一篇非常有趣的文章中,Allen Wirfs Brock解释了如何在不具体化(本机)堆栈的情况下实现块闭包

从他透露的许多想法中,有一个我不太理解,我认为在这里问一下是个好主意。他说:

如果在创建块时将变量的副本放置在闭包中,则在块的生命周期内永远无法分配的任何变量(例如,封闭方法和块的参数)无需放置在环境中

有两件事我不太清楚:

  • 为什么使用只读变量的两个副本比将变量移动到环境中要快?是因为封闭上下文访问堆栈中的(原始)变量会更快吗
  • 我们如何确保这两个变量保持同步
  • 问题1肯定还有另一个原因。否则,我看不到收益(与实现优化的成本相比)

    对于问题2,采用在方法中而不是在块中指定的非参数。为什么存储在堆栈中的oop在块的生命周期内保持不变


    我想我知道问题2的答案:因为块的执行不能与方法的执行交织在一起,也就是说,当块存在时,封闭上下文不会运行。但是,当块处于活动状态时,是否有任何方法可以临时修改堆栈?

    多亏了@aka.nice的评论,我在Clement Bera的帖子中找到了这两个问题的答案,该帖子的阅读既令人愉快又清晰

    对于Q1,我们首先假设Allen的评论意味着只读变量的副本可以放在块的堆栈中,就好像它是块的本地临时变量一样。这样做的好处只有在块外定义并在块内使用的所有变量从未写入块中时才会体现出来。在这些情况下,不需要创建环境数组,也不需要发出任何prolog或epilog来处理它

    访问堆栈变量的机器代码相当于访问环境变量所需的机器代码,因为一旦将
    edi
    设置为指向环境数组,第一个将使用
    [ebp+offset]
    来寻址位置,而第二个将使用
    [edi+offest]
    tempVector
    在Clement的符号中)因此,如果一些但不是所有的环境变量都是只读的,那么就没有收益

    第二个问题也在Clement的优秀博客中得到了回答。是的,还有另一种方法可以打破块堆栈中原始变量与其副本之间的同步:调试器(如aka.nice所说!)如果程序员修改封闭上下文中的变量,调试器将需要检测该操作并更新副本。如果程序员修改块堆栈中保存的副本,情况也是如此

    我很高兴我决定把这个问题贴在这里。我从aka.nice和Clement Bera那里得到的帮助,加上一些人通过电子邮件给我的评论,大大增强了我的理解力


    最后一句话。Wirfs Brock声称避免方法上下文的具体化是强制性的。我倾向于同意。但是,如果具体化遵循轻量级模式,则可以更好地实现这些数据结构上的许多重要操作。更准确地说,在调试时,可以使用“查看器”对这些上下文建模指向本机堆栈,并使用两个索引来划分与分析中的激活相对应的部分。这既高效又干净,两种技术的结合带来了世界上最好的结果,因为你可以同时拥有速度和表现力。Smalltalk令人惊讶。

    有趣的是,clement bera只是blogged关于闭包,感谢你的链接,你似乎有着相同的关注点。这是一个非常清晰的说明。(虽然选择器中有一个输入错误,它应该读ZooKeeper>>freeAllAnimals;-)