PHP 中 FOR 与 FOREACH 的性能 [英] Performance of FOR vs FOREACH in PHP

查看:87
本文介绍了PHP 中 FOR 与 FOREACH 的性能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先,我知道在 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 更快
  • PHPs foreach 复制它迭代的数组;为了加快速度,您需要使用引用
  • 代码如下:$key = array_keys($aHash);$size = sizeOf($key);
    for ($i=0; $i <$size; $i++)
    foreach

这是我的问题.我写了这个测试脚本:http://pastebin.com/1ZgK07US 并且无论我运行脚本多少次,我得到这样的东西:

foreach 1.1438131332397foreach(使用参考)1.2919359207153为 1.4262869358063foreach(哈希表)1.5696921348572对于(哈希表)2.4778981208801

简而言之:

  • foreach 比带有引用的 foreach 更快
  • foreachfor
  • foreachfor 对于哈希表要快

谁能解释一下?

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

PHP 5.3.0 版


回答在人们的帮助下,我能够拼凑出所有问题的答案.我将在这里总结它们:

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

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

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

解决方案

我个人的观点是使用上下文中有意义的内容.我个人几乎从不使用 for 进行数组遍历.我将它用于其他类型的迭代,但 foreach 太简单了......在大多数情况下,时间差异将很小.

需要注意的大事是:

for ($i = 0; $i 

这是一个昂贵的循环,因为它在每次迭代时调用计数.只要你不这样做,我认为这并不重要......

至于引用有所不同,PHP使用copy-on-write,所以如果不写入数组,循环时开销相对较小.但是,如果您开始修改数组中的数组,您就会开始看到它们之间的差异(因为需要复制整个数组,而引用只能修改内联)...

对于迭代器,foreach 等价于:

$it->rewind();而 ($it->valid()) {$key = $it->key();//如果使用 $key =>$value 语法$value = $it->current();//这里的循环内容$it->next();}

至于有更快的迭代方法,这实际上取决于问题.但我真的需要问,为什么?我理解想让事情变得更有效率,但我认为你是在浪费时间进行微优化.记住,过早优化是万恶之源...

根据评论,我决定进行快速基准测试...

$a = array();对于 ($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, "秒\n";$start = microtime(true);foreach ($a as $k => &$v) {$v = $v + 1;}echo "Completed in ", microtime(true) - $start, "秒\n";$start = microtime(true);foreach ($a as $k => $v) {}echo "Completed in ", microtime(true) - $start, "秒\n";$start = microtime(true);foreach ($a as $k => &$v) {}echo "Completed in ", microtime(true) - $start, "秒\n";

结果:

在 0.0073502063751221 秒内完成在 0.0019769668579102 秒内完成在 0.0011849403381348 秒内完成在 0.00111985206604 秒内完成

所以如果你在循环中修改数组,使用引用会快几倍...

而且仅引用的开销实际上比复制数组要少(这是在 5.3.2 上)......所以它看起来(至少在 5.3.2 上)好像引用明显更快......

使用 PHP 8.0 我得到以下内容:

在 0.0005030632019043 秒内完成在 0.00066304206848145 秒内完成在 0.00016379356384277 秒内完成在 0.00056815147399902 秒内完成

多次重复此测试,排名结果一致.

First of all, I understand in 90% of applications the performance difference is completely irrelevant, but I just need to know which is the faster construct. That and...

The information currently available on them on the net is confusing. A lot of people say foreach is bad, but technically it should be faster since it's suppose to simplify writing a array traversal using iterators. Iterators, which are again suppose to be faster, but in PHP are also apparently dead slow (or is this not a PHP thing?). I'm talking about the array functions: next() prev() reset() etc. well, if they are even functions and not one of those PHP language features that look like functions.

To narrow this down a little: I'm not interesting in traversing arrays in steps of anything more than 1 (no negative steps either, ie. reverse iteration). I'm also not interested in a traversal to and from arbitrary points, just 0 to length. I also don't see manipulating arrays with more than 1000 keys happening on a regular basis, but I do see a array being traversed multiple times in the logic of a application! Also as for operations, largely only string manipulation and echo'ing.

Here are few reference sites:
http://www.phpbench.com/
http://www.php.lt/benchmark/phpbench.php

What I hear everywhere:

  • foreach is slow, and thus for/while is faster
  • PHPs foreach copies the array it iterates over; to make it faster you need to use references
  • code like this: $key = array_keys($aHash); $size = sizeOf($key);
    for ($i=0; $i < $size; $i++)
    is faster than a foreach

Here's my problem. I wrote this test script: http://pastebin.com/1ZgK07US and no matter how many times I run the script, I get something like this:

foreach 1.1438131332397
foreach (using reference) 1.2919359207153
for 1.4262869358063
foreach (hash table) 1.5696921348572
for (hash table) 2.4778981208801

In short:

  • foreach is faster than foreach with reference
  • foreach is faster than for
  • foreach is faster than for for a hash table

Can someone explain?

  1. Am I doing something wrong?
  2. Is PHP foreach reference thing really making a difference? I mean why would it not copy it if you pass by reference?
  3. What's the equivalent iterator code for the foreach statement; I've seen a few on the net but each time I test them the timing is way off; I've also tested a few simple iterator constructs but never seem to get even decent results -- are the array iterators in PHP just awful?
  4. Are there faster ways/methods/constructs to iterate though a array other than FOR/FOREACH (and WHILE)?

PHP Version 5.3.0


Edit: Answer With help from people here I was able to piece together the answers to all question. I'll summarize them here:

  1. "Am I doing something wrong?" The consensus seems to be: yes, I can't use echo in benchmarks. Personally, I still don't see how echo is some function with random time of execution or how any other function is somehow any different -- that and the ability of that script to just generate the exact same results of foreach better than everything is hard to explain though just "you're using echo" (well what should I have been using). However, I concede the test should be done with something better; though a ideal compromise does not come to mind.
  2. "Is PHP foreach reference thing really making a difference? I mean why would it not copy it if you pass by reference?" ircmaxell shows that yes it is, further testing seems to prove in most cases reference should be faster -- though given my above snippet of code, most definitely doesn't mean all. I accept the issue is probably too non-intuitive to bother with at such a level and would require something extreme such as decompiling to actually determine which is better for each situation.
  3. "What's the equivalent iterator code for the foreach statement; I've seen a few on the net but each time I test them the timing is way off; I've also tested a few simple iterator constructs but never seem to get even decent results -- are the array iterators in PHP just awful?" ircmaxell provided the answer bellow; though the code might only be valid for PHP version >= 5
  4. "Are there faster ways/methods/constructs to iterate though a array other than FOR/FOREACH (and WHILE)?" Thanks go to Gordon for the answer. Using new data types in PHP5 should give either a performance boost or memory boost (either of which might be desirable depending on your situation). While speed wise a lot of the new types of array don't seem to be better than array(), the splpriorityqueue and splobjectstorage do seem to be substantially faster. Link provided by Gordon: http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/

Thank you everyone who tried to help.

I'll likely stick to foreach (the non-reference version) for any simple traversal.

解决方案

My personal opinion is to use what makes sense in the context. Personally I almost never use for for array traversal. I use it for other types of iteration, but foreach is just too easy... The time difference is going to be minimal in most cases.

The big thing to watch for is:

for ($i = 0; $i < count($array); $i++) {

That's an expensive loop, since it calls count on every single iteration. So long as you're not doing that, I don't think it really matters...

As for the reference making a difference, PHP uses copy-on-write, so if you don't write to the array, there will be relatively little overhead while looping. However, if you start modifying the array within the array, that's where you'll start seeing differences between them (since one will need to copy the entire array, and the reference can just modify inline)...

As for the iterators, foreach is equivalent to:

$it->rewind();
while ($it->valid()) {
    $key = $it->key();     // If using the $key => $value syntax
    $value = $it->current();

    // Contents of loop in here

    $it->next();
}

As far as there being faster ways to iterate, it really depends on the problem. But I really need to ask, why? I understand wanting to make things more efficient, but I think you're wasting your time for a micro-optimization. Remember, Premature Optimization Is The Root Of All Evil...

Edit: Based upon the comment, I decided to do a quick benchmark run...

$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";

And the results:

Completed in 0.0073502063751221 Seconds
Completed in 0.0019769668579102 Seconds
Completed in 0.0011849403381348 Seconds
Completed in 0.00111985206604 Seconds

So if you're modifying the array in the loop, it's several times faster to use references...

And the overhead for just the reference is actually less than copying the array (this is on 5.3.2)... So it appears (on 5.3.2 at least) as if references are significantly faster...

EDIT: Using PHP 8.0 I got the following:

Completed in 0.0005030632019043 Seconds
Completed in 0.00066304206848145 Seconds
Completed in 0.00016379356384277 Seconds
Completed in 0.00056815147399902 Seconds

Repeated this test numerous times and ranking results were consistent.

这篇关于PHP 中 FOR 与 FOREACH 的性能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆