The following blocks run a loop assigning the topic to a variable $var:
my $var; is outside the loopmy $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)
简短版本:在没有任何运行时优化(类型专门化,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何时不是程序中的第一个循环时会变得更糟;感觉比“合理地优化此功能”的合理情况更像是一个错误。即使稍有不足,它仍然可以在轻微防御下始终保持巨大的改进!
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |