php - PHP 中 FOR 与 FOREACH 的性能

标签 php arrays performance foreach for-loop

首先,我知道在 90% 的应用程序中性能差异完全无关紧要,但我只需要知道哪个是更快的构造。那和...

目前网上关于它们的信息令人困惑。很多人说 foreach 不好,但从技术上讲它应该更快,因为它假设使用迭代器简化编写数组遍历的过程。迭代器,再次假设更快,但在 PHP 中显然也很慢(或者这不是 PHP 的东西?)。我说的是数组函数:next() prev() reset() 等等,如果它们是函数,而不是那些看起来像函数的 PHP 语言特性之一。

将范围缩小一点:我对以超过 1 的任何步长遍历数组并不感兴趣(也没有负步,即反向迭代)。我也对往返任意点的遍历不感兴趣,只是 0 到长度。我也没有看到定期发生超过 1000 个键的操作数组,但我确实看到在应用程序的逻辑中多次遍历数组!同样对于操作,主要只有字符串操作和回显。

以下是几个引用网站:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php

我到处听到的:

  • foreach很慢,因此 for/while更快
  • PHP foreach复制它迭代的数组;为了使其更快,您需要使用引用
  • 代码如下:$key = array_keys($aHash); $size = sizeOf($key);
    for ($i=0; $i < $size; $i++)
    foreach

  • 这是我的问题。我写了这个测试脚本:http://pastebin.com/1ZgK07US无论我运行脚本多少次,我都会得到这样的结果:
    foreach 1.1438131332397
    foreach (using reference) 1.2919359207153
    for 1.4262869358063
    foreach (hash table) 1.5696921348572
    for (hash table) 2.4778981208801
    

    简而言之:
  • foreachforeach 快引用
  • foreachfor
  • foreachfor 快对于哈希表

  • 有人可以解释一下吗?
  • 我做错了什么吗?
  • PHP foreach 引用的东西真的有所作为吗?我的意思是如果你通过引用传递它为什么不复制它?
  • foreach 语句的等效迭代器代码是什么?我在网上看到过一些,但每次我测试它们时,时间都相差甚远;我还测试了一些简单的迭代器构造,但似乎从来没有得到过像样的结果——PHP 中的数组迭代器是不是很糟糕?
  • 是否有更快的方法/方法/结构来迭代除 FOR/FOREACH(和 WHILE)以外的数组?

  • PHP 版本 5.3.0

    编辑:答案
    在人们的帮助下,我能够拼凑出所有问题的答案。我将在这里总结它们:
  • “我做错了什么吗?”共识似乎是:是的,我不能在基准测试中使用 echo。就我个人而言,我仍然不明白 echo 是一些具有随机执行时间的函数,或者任何其他函数有什么不同 - 以及该脚本生成完全相同的 foreach 结果的能力比一切都好解释虽然只是“你正在使用 echo ”(我应该使用什么)。但是,我承认测试应该用更好的方法来完成。虽然没有想到理想的妥协。
  • “PHP foreach 引用的东西真的有所作为吗?我的意思是,如果您通过引用传递,它为什么不复制它?” ircmaxell 表明是的,进一步的测试似乎证明在大多数情况下引用应该更快——尽管鉴于我上面的代码片段,绝对不是全部。我接受这个问题可能太不直观,无法在这样的级别上打扰,并且需要一些极端的东西,例如反编译来实际确定哪种情况更适合每种情况。
  • “foreach 语句的等效迭代器代码是什么;我在网上看到了一些,但每次我测试它们时,时间都相差甚远;我还测试了一些简单的迭代器结构,但似乎从未得到过像样的结果-- PHP 中的数组迭代器很糟糕吗?” ircmaxell 在下面提供了答案;尽管代码可能只对 PHP 版本 >= 5
  • 有效
  • “是否有更快的方法/方法/结构来迭代除 FOR/FOREACH(和 WHILE)以外的数组?”感谢戈登的回答。在 PHP5 中使用新的数据类型应该可以提高性能或提高内存(根据您的情况,这两者都可能是可取的)。虽然在速度方面,许多新类型的数组似乎并不比 array() 好,但 splpriorityqueue 和 splobjectstorage 似乎要快得多。戈登提供的链接:http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/

  • 感谢所有试图提供帮助的人。

    对于任何简单的遍历,我可能会坚持使用 foreach(非引用版本)。

    最佳答案

    我个人的意见是使用上下文中有意义的内容。我个人几乎从不使用 for用于数组遍历。我将它用于其他类型的迭代,但是 foreach太简单了……在大多数情况下,时差很小。
    需要注意的大事是:

    for ($i = 0; $i < count($array); $i++) {
    
    这是一个昂贵的循环,因为它在每次迭代时调用计数。只要你不这样做,我认为这并不重要......
    至于引用有所不同,PHP使用copy-on-write,所以如果不写入数组,循环时开销相对较小。但是,如果您开始修改数组中的数组,那么您将开始看到它们之间的差异(因为需要复制整个数组,而引用只能修改内联)...
    至于迭代器,foreach相当于:
    $it->rewind();
    while ($it->valid()) {
        $key = $it->key();     // If using the $key => $value syntax
        $value = $it->current();
    
        // Contents of loop in here
    
        $it->next();
    }
    
    至于是否有更快的迭代方法,这实际上取决于问题。但我真的需要问,为什么?我理解想让事情变得更有效率,但我认为你是在浪费时间进行微优化。记住,Premature Optimization Is The Root Of All Evil ...
    编辑:根据评论,我决定做一个快速的基准测试......
    $a = array();
    for ($i = 0; $i < 10000; $i++) {
        $a[] = $i;
    }
    
    $start = microtime(true);
    foreach ($a as $k => $v) {
        $a[$k] = $v + 1;
    }
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => &$v) {
        $v = $v + 1;
    }
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => $v) {}
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    $start = microtime(true);
    foreach ($a as $k => &$v) {}    
    echo "Completed in ", microtime(true) - $start, " Seconds\n";
    
    结果:
    Completed in 0.0073502063751221 Seconds
    Completed in 0.0019769668579102 Seconds
    Completed in 0.0011849403381348 Seconds
    Completed in 0.00111985206604 Seconds
    
    因此,如果您在循环中修改数组,则使用引用要快几倍......
    而仅仅引用的开销实际上比复制数组要少(这是在 5.3.2 上)......所以它看起来(至少在 5.3.2 上)好像引用明显更快......
    编辑:使用 PHP 8.0 我得到以下信息:
    Completed in 0.0005030632019043 Seconds
    Completed in 0.00066304206848145 Seconds
    Completed in 0.00016379356384277 Seconds
    Completed in 0.00056815147399902 Seconds
    
    多次重复此测试,排名结果一致。

    关于php - PHP 中 FOR 与 FOREACH 的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3430194/

    相关文章:

    php - 在 PHP 中读取 docx(Office Open XML)

    PHPMailer SMTP 错误 : Failed to connect to server

    Android 布局 - 不同屏幕分辨率和相同密度的图像

    php - 从 $类别中选择 *

    php - 与 FTP 服务器同步文件

    php - 尝试使用 ErrorDocument 时出现 404 Not Found 错误

    c - 在多个结构指针和数组中为结构指针的成员赋值

    arrays - 为什么在我的 if 语句中添加不等于空格会导致错误?

    java - 如何将java数组复制到javascript数组?

    "fast-moving"小表上的 mysql 索引性能