Chinaunix

标题: 子程序shift取参数,是否会增加CPU时钟周期? [打印本页]

作者: 3P用户    时间: 2011-06-21 16:27
标题: 子程序shift取参数,是否会增加CPU时钟周期?
my $var = shift; #出栈且赋值
与 my $var = $_[0]; 这种直接通过内存地址读取相比,时钟周期是否会增加?
作者: 兰花仙子    时间: 2011-06-21 16:30
my $var = shift; #出栈且赋值
与 my $var = $_[0]; 这种直接通过内存地址读取相比,时钟周期是否会增加?
3P用户 发表于 2011-06-21 16:27



    这种差别微小到可以忽略不计吧。。
真追求这点性能,还不如用C来写程序。
作者: zhlong8    时间: 2011-06-21 16:36
精神可嘉啊,直接算时钟周期。我最开始也只是算 bytecode
作者: 3P用户    时间: 2011-06-21 16:36
是滴,绝大多数情形下没有必要区分。
如果是在单进程模式下,循环处理2000个IO句柄,这类操作累加起来影响就不能忽略,我是想尽量优化。
作者: 兰花仙子    时间: 2011-06-21 16:38
是滴,绝大多数情形下没有必要区分。
如果是在单进程模式下,循环处理2000个IO句柄,这类操作累加起 ...
3P用户 发表于 2011-06-21 16:36



    shift是会慢一点。
作者: 3P用户    时间: 2011-06-21 16:49
精神可嘉啊,直接算时钟周期。我最开始也只是算 bytecode
zhlong8 发表于 2011-06-21 16:36



      也就是粗略估计一下。
作者: 3P用户    时间: 2011-06-21 16:49
shift是会慢一点。
兰花仙子 发表于 2011-06-21 16:38



    谢谢版主。
作者: DQP    时间: 2011-06-21 22:25
是滴,绝大多数情形下没有必要区分。
如果是在单进程模式下,循环处理2000个IO句柄,这类操作累加起 ...
3P用户 发表于 2011-06-21 16:36



    是会慢. 不过才2000次而已. 而且和IO比起来这完全可以忽略不计。
作者: 2gua    时间: 2011-06-21 22:26
肉眼看不到。
作者: sunway820    时间: 2011-06-22 00:19
这个细微的差异没有注意到
楼主有心了。。。
作者: flw    时间: 2011-06-22 13:32
楼主这是丢了西瓜捡芝麻啊。
同意仙子的说法。
作者: Monox    时间: 2011-06-22 14:38
本帖最后由 Monox 于 2011-06-22 14:39 编辑
shift是会慢一点。
兰花仙子 发表于 2011-06-21 16:38


shift 应该会快一点。不知是小骆驼书还是其它什么书上说过,在 C 语言里使用下标索引是很快的,但是在 Perl 里面显示的下标索引会降低速度,使用 shift, unshift 等会更快点。因为 Perl 对 AV 做过优化,让 AV 的常用操作比在 Perl 里直接使用下标索引更快。
于是我做了以下测试:

  1. #!/usr/bin/env perl

  2. use 5.12.0;
  3. use Benchmark qw(cmpthese);

  4. sub sum_a {
  5.     my $a = shift;
  6.     my $b = shift;
  7.     return $a + $b;
  8. }

  9. sub sum_b {
  10.     my $a = $_[0];
  11.     my $b = $_[1];
  12.     return $a + $b;
  13. }

  14. cmpthese(90000000, {
  15.         shift => &sum_a,
  16.         index => &sum_b
  17.     });

  18. # vim: sw=4 ts=4 ft=perl expandtab
复制代码
输出结果:

  1. $ perl test.pl
  2.              Rate index shift
  3. index 140625000/s    --   -3%
  4. shift 145161290/s    3%    --
复制代码
也就是说同时运行 90000000 次的话,使用 shift 比使用 index 要快 3%,不过,正如大家说的,这点差异是几乎可以忽略的。把 90000000 改成 10000000 以下的数的结果类似如下:
  1. $ perl test.pl
  2.             (warning: too few iterations for a reliable count)
  3.             (warning: too few iterations for a reliable count)
  4.              Rate shift index
  5. shift 100000000/s    --  -20%
  6. index 125000000/s   25%    --
复制代码

作者: Monox    时间: 2011-06-22 14:43
回复 12# Monox
把 cmpthese 改成 timethese 的结果:

  1.     $ perl test.pl
  2. Benchmark: timing 90000000 iterations of index, shift...
  3.      index:  1 wallclock secs ( 0.73 usr +  0.01 sys =  0.74 CPU) @ 121621621.62/s (n=90000000)
  4.      shift:  1 wallclock secs ( 0.28 usr + -0.02 sys =  0.26 CPU) @ 346153846.15/s (n=90000000)
  5.             (warning: too few iterations for a reliable count)
复制代码
注意最后说 90000000 还是不够喔,我就不继续上调这个次数了。
作者: zhlong8    时间: 2011-06-22 14:53
回复  Monox
把 cmpthese 改成 timethese 的结果:注意最后说 90000000 还是不够喔,我就不继续上调这个次 ...
Monox 发表于 2011-06-22 14:43



    你根本没有传入参数比较个什么? shift 可以直接检测出来 @_ 为空。
  1. use Benchmark;

  2. my @a = (1..1000000);
  3. my @b = (1..1000000);

  4. timethese 1, {
  5.     shift => sub {
  6.         my $b;
  7.         for (1 .. @a) {
  8.             $b = shift @a;
  9.         }
  10.     },
  11.     ref => sub {
  12.         my $b;
  13.         for (1 .. @b) {
  14.             $b = $b[$_];
  15.         }
  16.     }
  17. }
复制代码

作者: Monox    时间: 2011-06-22 14:58
回复 14# zhlong8
喔,一不小心忘了传参数了,我修改了一下代码,好像 index 比 shift 还是快点

  1. $ perl test.pl
  2. Benchmark: timing 90000000 iterations of index, shift...
  3.      index:  1 wallclock secs ( 0.71 usr + -0.01 sys =  0.70 CPU) @ 128571428.57/s (n=90000000)
  4.      shift:  0 wallclock secs ( 0.74 usr +  0.00 sys =  0.74 CPU) @ 121621621.62/s (n=90000000)
复制代码
不好意思刚才搞错了。
作者: jason680    时间: 2011-06-22 15:25
看半天,看不出所以然....

没有说参数只能shift或$_[n]
foreach(@_)直接用不就好了....

11楼的"丢了西瓜捡芝麻啊"....妙哉妙哉
作者: flw    时间: 2011-06-22 15:35
你根本没有传入参数比较个什么? shift 可以直接检测出来 @_ 为空。
zhlong8 发表于 2011-06-22 14:53



    你这个测试很怪异,感觉不足信的样子。
作者: zhlong8    时间: 2011-06-22 15:43
你这个测试很怪异,感觉不足信的样子。
flw 发表于 2011-06-22 15:35



    只想比较 shift 和索引两种方法的速度,可是 shift 会改变数组一时想不出来好办法了
作者: flw    时间: 2011-06-22 15:50
我这里测试的结果是 index 快,5.8.5 下快 12%,5.14 下快 9%
  1. #!/usr/bin/perl

  2. use Benchmark qw(:all);

  3. sub test_shift {
  4.     my $left  = shift;
  5.     my $right = shift;

  6.     return $left + $right;
  7. }

  8. sub test_index {
  9.     my $left  = $_[0];
  10.     my $right = $_[1];

  11.     return $left + $right;
  12. }

  13. cmpthese( -1, {
  14.     shift => sub {
  15.         test_shift( 1, 2 );
  16.     },
  17.     index => sub {
  18.         test_index( 1, 2 );
  19.     }
  20. } );
复制代码

作者: flw    时间: 2011-06-22 15:52
只想比较 shift 和索引两种方法的速度,可是 shift 会改变数组一时想不出来好办法了
zhlong8 发表于 2011-06-22 15:43



    但楼主问的是子程序取参数,所以起码得搞个 sub 糊弄糊弄吧。
作者: zhlong8    时间: 2011-06-22 16:03
但楼主问的是子程序取参数,所以起码得搞个 sub 糊弄糊弄吧。
flw 发表于 2011-06-22 15:52



    最终比较的不还是 shift 和索引的差别。用函数包起来会夹杂大量的多余指令,差异会被摊薄
作者: Monox    时间: 2011-06-22 16:07
我又测试了两次,都是 shift 更快,所以,到底哪个快这个好像也不太好说。
一次代码如下:

  1. #!/usr/bin/env perl

  2. use 5.12.0;
  3. use Benchmark qw(timethese);

  4. sub sum_a {
  5.     my $a = shift;
  6.     my $b = shift;
  7.     return $a + $b;
  8. }

  9. sub sum_b {
  10.     my $a = $_[0];
  11.     my $b = $_[1];
  12.     return $a + $b;
  13. }

  14. timethese(90000000, {
  15.         shift => sub {
  16.             sum_a(3, 5)
  17.         },
  18.         index => sub {
  19.             sum_b(3, 5)
  20.         }
  21.     });

  22. # vim: sw=4 ts=4 ft=perl expandtab
复制代码
输出:

  1. $ perl test.pl
  2. Benchmark: timing 90000000 iterations of index, shift...
  3.      index: 46 wallclock secs (45.23 usr +  0.02 sys = 45.25 CPU) @ 1988950.28/s (n=90000000)
  4.      shift: 43 wallclock secs (42.33 usr +  0.03 sys = 42.36 CPU) @ 2124645.89/s (n=90000000)
复制代码
另一次从 flw 版主那儿偷学来一个参数(-1):

  1. #!/usr/bin/env perl

  2. use 5.12.0;
  3. use Benchmark qw(cmpthese);

  4. sub sum_a {
  5.     my $a = shift;
  6.     my $b = shift;
  7.     return $a + $b;
  8. }

  9. sub sum_b {
  10.     my $a = $_[0];
  11.     my $b = $_[1];
  12.     return $a + $b;
  13. }

  14. cmpthese(-1, {
  15.         shift => sub {
  16.             sum_a(3, 5)
  17.         },
  18.         index => sub {
  19.             sum_b(3, 5)
  20.         }
  21.     });

  22. # vim: sw=4 ts=4 ft=perl expandtab
复制代码
输出:
  1. $ perl test2.pl
  2.            Rate index shift
  3. index 1872457/s    --   -6%
  4. shift 1989485/s    6%    --
复制代码
这次我没有写错什么吧。
作者: flw    时间: 2011-06-22 16:07
最终比较的不还是 shift 和索引的差别。用函数包起来会夹杂大量的多余指令,差异会被摊薄
zhlong8 发表于 2011-06-22 16:03



    那可不好说。万一在取参数这块有什么优化,那就完全不是同一个问题了。
作者: Monox    时间: 2011-06-22 16:08
最终比较的不还是 shift 和索引的差别。用函数包起来会夹杂大量的多余指令,差异会被摊薄
zhlong8 发表于 2011-06-22 16:03


这个我可以肯定是不一样的。Perl 5.14 的 perldelta 里明确说了在函数调用里 shift 比 shift @_ 要快。
作者: zhlong8    时间: 2011-06-22 16:14
本帖最后由 zhlong8 于 2011-06-22 16:15 编辑

好吧你们赢了

想起之前看精通正则表达式学了一堆优化技巧,结果 Perl 全都已经优化了,一点成就感都没有。那咱就具体情况具体分析吧
作者: flw    时间: 2011-06-22 16:16
好吧你们赢了

想起之前看精通正则表达式学了一堆优化技巧,结果 Perl 全都已经优化了,一点成就感 ...
zhlong8 发表于 2011-06-22 16:14



    所以只有逻辑才是可靠的啊。乌鸦是黑的并不能证明北极熊是白的呀。
作者: Monox    时间: 2011-06-22 16:32
我自己检讨一下,我测试的是 shift 比 index 快,数据在前面的回复里已经给出了。我要检讨的是我在一个15楼里说 index 比 shift 快是因为我是在函数的第一句直接修改了 @_ 的值。
这大概说明了 shift 只在参数传递时可能会比 index 快,但是在一般情况下应该是 index 更快。因此也会有参数传递的优化不足以超过 index 的效率的情况,就像 flw 版主说过的测试结果。
我之前使用的测试环境都是 Linux x64, Perl 5.14.1。
作者: zhlong8    时间: 2011-06-22 16:33
才传这么几个参数根本不可能成为瓶颈,楼主如果真对速度有着无尽的渴望那就把函数都 inline 了吧,提升绝对是这里的百倍
作者: flw    时间: 2011-06-22 16:43
可惜 Perl 没有 inline,很多时候我确实挺喜欢 inline 的。
尤其是做一些统计类的程序时,函数可以让代码结构更清晰,
但是函数体本身又很轻,函数调用的开销比重就很大。所以很矛盾。
作者: 3P用户    时间: 2011-06-23 02:37
谢谢,谢谢大家!
这么一个突发奇想的问题,引得大家这么热心,尽管是夏天,但还是让人感觉到温暖。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2