msgbartop
PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 – 左手代码 右手诗
msgbarbottom

07 Apr 09 如何写出最快的循环

你知道怎么写出最快的循环么?

刚刚在晓东郭的blog看到一个有趣的问题” PHP中 $i++ 和 ++$i 的区别 “:

方式一:

$begin = time();
$i = 0;
while(++$i < 10000)
{
  $j = 0;
  while(++$j < 10000)
    ;
  ;
}
$end = time();

时间 : 16s

方式二:

$begin = time();
$i = 0;
while($i < 10000)
{
  $j = 0;
  while($j < 10000)
    ++$j;
  ++$i;
}
$end = time();

时间:13s

方式三:

$begin = time();
$i = 0;
while($i < 10000)
{
  $j = 0;
  while($j < 10000)
    $j++;
  $i++;
}
$end = time();

时间:15s

方式四:

$begin = time();
$i = 0;
while($i++ < 10000)
{
  $j = 0;
  while($j++ < 10000)
    ;
  ;
}
$end = time();
时间:13s

呵呵, 为什么会这样呢?
对比第一种方法和第二种方法, 因为在PHP中, 最终被执行的是OPCODE, 每行opline都有俩个操作数, 对于操作数来说, 一般有3种类型的存取方式, 临时变量, 变量, 和编译时变量, 这三种变量其中, 存取最快的是第三种, 编译器变量, 在OpCode执行过程中, 会讲一个变量的加一级引用存储在一个hash结构中, 用来加快存取速度.

在第一种方法中:

$i = 0;
while(++$i < 10000)
{
  $j = 0;
  while(++$j < 10000)
    ;
  ;
}

因为对于++$i来说, 我们需要得到它的返回值, 来和10000做比较, 这样就会使得PHP在编译的时候 , 生成一个变量(IS_VAR), 来保存自增的结果 , 也就是说, 这个时候用到了opline的return操作数.
然后, PHP会拿这个变量(IS_VAR)来和10000做比较.

而对于第二种方式:

$i = 0;
while($i < 10000)
{
  $j = 0;
  while($j < 10000)
    ++$j;
  ++$i;
}

这个过程中, $i已经优化成了编译变量(IS_CV), 而对于++$i, 因为我们不需要保存他的返回值, 所以也只是直接对编译变量进行自增..

也就是说, 方法一和方法二的速度差异, 就在于 对于方式二, 我们一直都在实用编译变量.. 编译变量的存取速度远快于变量(IS_VAR)

再来看第三种和第四种方式:

//3:
$i = 0;
while($i < 10000)
{
  $j = 0;
  while($j < 10000)
    $j++;
  $i++;
}

//4:
$i = 0;
while($i++ < 10000)
{
  $j = 0;
  while($j++ < 10000)
    ;
  ;
}

我们知道后缀自增(POST_INC), 会返回一个对原值的copy, 然后自增.
对于第四种方式, $i++以后, ZE会将$i的原值, 存储在一个临时变量(IS_TMP_VAR). 并且会拿这个临时变量和10000对比.
所以, 严格来讲, 这部分的速度比起第一种方式来说是会慢一些的.

而第三种方式慢在, 因为对$i++的返回值没有使用, 在语法分析阶段, $j++会归约成(rw_variable T_INC->expr_without_variable->expr, expr+’;’ => zend_do_free). 所以ZE就会安排一条opline, free掉这个临时变量….


分享到:



Related Posts:

Tags: ,

22 Responses to “如何写出最快的循环”

  1. gump |

    第一种是不是循环的次数 和后面的不一样?版本5.5.18

  2. nange |

    哦,还真是第三个快啊,我在我的机子上跑这段代码,第一个用了5秒,第二个没试,直接式第三个,结果是用时0秒,看来还是需要弄懂PHP的工作原理呀。

  3. emerald_zj |

    我也同意用中文!!好容易找一个不是英文的站点

  4. 雪候鸟 |

    I’m sorry , no

  5. yurtdisi egitim |

    is this web site availible in English?

  6. 雪候鸟 |

    IS_TMP_VAR和IS_CV都是从execute_data结构中获取的.
    跟踪后发现,俩者的速度应该差别不是很大.都是一个类似数组结构的”cache”

  7. tonado |

    是5.2.8

    刚才说错了,第四种的POST_INC是有返回值存到临时变量里的,刚好用来比较,即

    第四种是:
    POST_INC !0 =>RES[~1]
    IS_SMALLER ~1, 1000 =>RES[~2]

    第二种是:
    IS_SMALLER !0, 1000 =>RES[~1]

    PRE_INC !0

    第一种是:
    PRE_INC !0 =>RES[$1]
    IS_SMALLER $1, 1000 =>RES[~2]

    四和二互有胜负就先不管了,理论上感觉二应该要比四快,但是我测了很多次结果第四种就没输过第一种,所有才有IS_TMP_VAR会不会比IS_VAR快的疑问,至于IS_CV,会不会它会做额外的工作,导致有时候反而不如一气呵成的IS_TMP_VAR呢?

  8. 雪候鸟 |

    哦? 从理论上来讲, 应该是IS_CV最快. 你的PHP版本是?

  9. tonado |

    刚才我测试了一下,测了5次,结果如下

    9.7706120014191
    9.0341799259186
    10.309438943863
    8.8307638168335

    9.7692799568176
    8.8732059001923
    10.170838117599
    8.8990998268127

    9.7464888095856
    8.8881361484528
    10.337028026581
    8.9553401470184

    9.7715139389038
    8.9210159778595
    10.189666032791
    8.8990459442139

    9.7989208698273
    9.0310311317444
    10.350558996201
    8.9781529903412

    结果显示,第四种方法应该是最快的(或者说第四种和第二种并列第一),并不像laruence所说的比第一种慢,这意味着IS_TEM_VAR要比IS_VAR快?好像这是唯一的解释了…让我意外的是第四种竟然大多数情况下比第二种还要快,既然二四的前/后自增都不需要返回值,假定POST_INC和PRE_INC性能一样的话,那么就是说使用!进行IS_SMALLER运算的第二种跟使用~的第四种半斤八两?甚至,大多数情况下还要差?

  10. 雪候鸟 |

    有理,是不会计算的.

  11. TinTin |

    我觉得不是预编译的问题,因为随着循环次数的增加,PHP的消耗时间呈一次函数形式增长,如果存在预编译问题,哪么PHP循环一百次和JAVA循环时间应该差很大,但是PHP要快于JAVA

    对了,问个问题,PHP预编译的时间会不计算在$start_time=time();$end_time=time();之中?

  12. 雪候鸟 |

    恩, JAVA是预编译么. 性能来讲JSP确实要比PHP来的快些

  13. TinTin |

    我在JAVA1.6下测试(不是JSP,不过应该差不多) JAVA要比PHP强悍,以亿次循环以毫秒为单位 说说测试结果吧(平均): 第一种:208MS 第二种:228MS 第三种:228MS 第四种:210MS

  14. 网鬼 |

    还好一直用第二种

  15. 古嗣小井 |

    想请教个问题while的写法:
    $i = 0;
    while($i++ < 10000)
    {
    $j = 0;
    while($j++ < 10000)
    ;
    ;
    }
    一般我都是这样写的:
    $i = 0;
    while($i++ < 10000)
    {
    $j = 0;
    while($j++ < 10000){
    ;
    }
    ;
    }
    省掉第二个while的{}有什么特别的意义么?

  16. z.y.f |

    学习……

  17. unnamed |

    @eve, 还是很简单明了的

  18. 雪候鸟 |

    @明城, 恩, 本文的重点在于PHP特别性. :)

  19. anders |

    哈哈,Thanks.

  20. 明城 |

    其实这个也有论断,可以参考下这里 http://www.gracecode.com/archives/1426/

  21. 雪候鸟 |

    @eve, …回家待着去….

  22. eve |

    看球不懂~

Leave a Reply

*