以下块运行循环,将主题分配给变量$var
:
my $var;
在循环之外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;
}
每个块的样本输出持续时间(秒)如下:
0.5938845
1.8251226
2.60700803
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
简短版本:在没有任何运行时优化(类型专门化,JIT等)的世界中,时间安排将符合您的期望。优化程序处理每个示例的效果会影响此处的时间安排。
首先,在没有任何运行时优化的情况下运行代码很有趣。在我当前使用的机器上(相当慢)的VM中,坚持MVM_SPESH_DISABLE=1
使用环境会导致以下情况:
13.92366942
16.235372
14.4329288
这些具有某种直观意义:
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
何时不是程序中的第一个循环时会变得更糟?感觉比“合理地优化此功能”的情况更像是一个错误。在稍有防御的情况下,即使它没有期望的那么大,它仍然始终能够取得巨大的进步!
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句