What happens when a declarator (my/state) is in a for block?

drc*_*law 9 scope perl6

The following blocks run a loop assigning the topic to a variable $var:

  • The first one the my $var; is outside the loop
  • 第二个my $var;在循环内
  • 最后state $var;是循环内
my $limit=10_000_000;
{
    my $var;
    for ^$limit { $var =$_; }
    say now  - ENTER now;
}
{
    for ^$limit { my $var; $var=$_; }
    say now  - ENTER now;
}
{
    for ^$limit { state $var; $var=$_; }
    say now  - ENTER now;
}
Run Code Online (Sandbox Code Playgroud)

每个块的样本输出持续时间(秒)如下:

0.5938845                                                                                                                                 
1.8251226                                                                                                                                 
2.60700803  
Run Code Online (Sandbox Code Playgroud)

https://docs.perl6.org/syntax/state运动state变量上的文档具有与相同的词法作用域my。从功能上讲,代码块1和块3将在对相应循环块的多次调用中实现相同的持久存储。

为什么state(和内部my)版本需要更多时间?它还在做什么?

编辑: 类似于@HåkonHægland的注释,如果我剪切并粘贴了上面的代码,以便每个块总共运行3次,则my $var外部循环的时序变化会很明显(第一种情况):

0.600303                                                                                                                                  
1.7917011                                                                                                                                 
2.6640811                                                                                                                                 

1.67793597                                                                                                                                
1.79197091                                                                                                                                
2.6816156                                                                                                                                 

1.795679                                                                                                                                  
1.81233942                                                                                                                                
2.77486777
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 6

简短版本:在没有任何运行时优化(类型专门化,JIT等)的世界中,时间安排将符合您的期望。优化程序处理每个示例的效果会影响此处的时间安排。

首先,在没有任何运行时优化的情况下运行代码很有趣。在我当前使用的机器上(相当慢)的VM中,坚持MVM_SPESH_DISABLE=1使用环境会导致以下情况:

13.92366942
16.235372
14.4329288
Run Code Online (Sandbox Code Playgroud)

这些具有某种直观意义:

  • 在第一种情况下,我们在块的外部范围中声明了一个简单的词法变量
  • 在第二种情况下,我们必须Scalar在循环中每次分配一个额外的分配,然后进行垃圾回收,这会占用额外的时间
  • 在第三种情况下,我们使用state变量。甲state变量存储在封闭件的代码对象,然后被复制到在输入时间的呼叫帧。这比Scalar每次分配一个新程序都便宜,但是比根本不需要执行该操作要多得多的工作。

接下来,让我们运行3个启用了优化器的程序,每个示例都在其自己的隔离程序中。

  • 第一个出现在0.86298831,速度提高了16倍。去优化器!它已内联循环主体。
  • 第二个出现在1.2288566,速度提高了13倍。也不要太破旧。它再次内联循环主体。(一旦逃逸分析器足够聪明以消除Scalar分配,这种情况在将来也将变得更加便宜。)
  • 第三个出现在2.0695035,速度提高了7倍。相对而言,这并不令人印象深刻(即使仍是一个很大的改进),主要原因是它没有内联循环体。为什么?因为它尚不知道如何内联使用状态变量的代码。(如何看待:MVM_SPESH_INLINE_LOG=1在环境中运行,输出结果为:Can NOT inline (1) with bytecode size 78 into (3): cannot inline code that declares a state variable。)

简而言之,此处的主要因素是循环主体的内联,并且目前尚不可能使用状态变量。

现在还不清楚为什么优化器在外部声明$var何时不是程序中的第一个循环时会变得更糟;感觉比“合理地优化此功能”的合理情况更像是一个错误。即使稍有不足,它仍然可以在轻微防御下始终保持巨大的改进!