为什么 substr-lvalue 比四参数 substr 快?

Why is substr-lvalue faster than four-arg substr?

this question 开始,我们对这两个变体进行了基准测试,

substr( $foo, 0, 0 ) = "Hello ";
substr( $foo, 0, 0, "Hello " );

在其中我们发现 substr-lvalue 更快。池上说,

How is 4-arg substr slower than lvalue substr (which must create a magical scalar, and requires extra operations)??? – ikegami

说实话,我还认为它会慢得多,只是提到它,因为它是由其他人提出的。纯粹出于好奇,

为什么在上述用例中 substr-左值比四参数 substr 快?

这只是一个糟糕的基准测试结果。

当我复制你的结果时,我在 Windows Susbsytem for Linux 上使用 Unbuntu 上的 perl。假设性能对该系统的外部因素很敏感。

即使在同一台计算机上使用 Windows (Strawberry Perl) 的本机构建,我的结果也大相径庭:

                   Rate        substr substr_valute   multiconcat
                  Rate substr_valute        substr   multiconcat
substr_valute 6997958/s            --           -0%          -27%
substr        7007667/s            0%            --          -26%
multiconcat   9533733/s           36%           36%            --

                   Rate        substr substr_valute   multiconcat
substr        6795650/s            --           -0%          -10%
substr_valute 6805545/s            0%            --          -10%
multiconcat   7526593/s           11%           11%            --

                    Rate        substr substr_valute   multiconcat
substr         7513339/s            --          -22%          -28%
substr_valute  9693997/s           29%            --           -6%
multiconcat   10367639/s           38%            7%            --

                    Rate        substr   multiconcat substr_valute
substr         8791152/s            --          -13%          -14%
multiconcat   10139954/s           15%            --           -1%
substr_valute 10240638/s           16%            1%            --

时间这么小,机器太忙,无法准确读数。

(在某处有关于微优化的要点...)

我讨厌 运行 我共享的 linux 虚拟主机上的基准测试,但它通常会产生更加一致的结果。今天也不例外。

                   Rate        substr substr_valute   multiconcat
substr        4293130/s            --           -3%          -13%
substr_valute 4407446/s            3%            --          -11%
multiconcat   4938717/s           15%           12%            --

                   Rate substr_valute        substr   multiconcat
substr_valute 4289732/s            --           -2%          -16%
substr        4356113/s            2%            --          -15%
multiconcat   5096889/s           19%           17%            --

(我用 -3 而不是 100_000_000。)

所有差异都在 3% 或更少,这并不显着。据我所知,一个并不比另一个慢。

事实上,人们不应该期待有什么不同。正如 Dave Mitchell 指出的那样,substr( $foo, 0, 0 ) = "Hello "; 自 5.16 以来被优化为实际上等同于 substr( $foo, 0, 0, "Hello " ); 的东西(在 5.20 中有所改进)。

$ perl -MO=Concise,-exec -e'substr( $foo, 0, 0, "Hello " );'
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <#> gvsv[*foo] s
4  <$> const[IV 0] s
5  <$> const[IV 0] s
6  <$> const[PV "Hello "] s
7  <@> substr[t2] vK/4
8  <@> leave[1 ref] vKP/REFC
-e syntax OK

$ perl -MO=Concise,-exec -e'substr( $foo, 0, 0 ) = "Hello ";'
1  <0> enter
2  <;> nextstate(main 1 -e:1) v:{
3  <$> const[PV "Hello "] s
4  <#> gvsv[*foo] s
5  <$> const[IV 0] s
6  <$> const[IV 0] s
7  <@> substr[t2] vKS/REPL1ST,3
8  <@> leave[1 ref] vKP/REFC
-e syntax OK

(唯一的区别是操作数传递的顺序,使用 REPL1ST 标志发出信号。)

从5.16.0开始,lvalue+assign变体被优化为4-arg变体(虽然nulled-out NOOP赋值op在5.20.0之前仍然在执行路径中,这稍微减慢了速度) .