PHP 中 FOR 与 FOREACH 的性能对比
首先,我知道在 90% 的应用程序中,性能差异完全无关紧要,但我只需要知道哪个是更快的构造.那和...
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...
目前在网上获得的信息令人困惑.很多人说 foreach 不好,但从技术上讲,它应该更快,因为它可以简化使用迭代器编写数组遍历的过程.迭代器,再次被认为更快,但在 PHP 中也显然非常慢(或者这不是 PHP 的东西?).我说的是数组函数:next() prev() reset() 等等,如果它们是偶数函数而不是那些看起来像函数的 PHP 语言特性之一.
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.
缩小一点:我对以超过 1 的步数遍历数组并不感兴趣(也没有负步数,即反向迭代).我也对往返任意点的遍历不感兴趣,只是长度为 0.我也没有看到定期操作超过 1000 个键的数组,但我确实看到一个数组在应用程序的逻辑中被多次遍历!同样对于操作,主要是字符串操作和回显.
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.
这里有几个参考网站:
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
快
foreach
is slow, and thusfor
/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);
is faster than a
for ($i=0; $i < $size; $i++)foreach
这是我的问题.我写了这个测试脚本: http://pastebin.com/1ZgK07US 并且不管我运行了多少次脚本,我得到这样的结果:
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
简而言之:
foreach
比foreach
with reference 快foreach
比for
快foreach
比for
更快
foreach
is faster thanforeach
with referenceforeach
is faster thanfor
foreach
is faster thanfor
for a hash table
谁能解释一下?
- 我做错了吗?
- PHP foreach 引用的东西真的有影响吗?我的意思是如果你通过引用它为什么不复制它?
- foreach 语句的等效迭代器代码是什么?我在网上看到过一些,但每次我测试它们的时间都差了;我还测试了一些简单的迭代器构造,但似乎从来没有得到过像样的结果——PHP 中的数组迭代器是不是很糟糕?
- 除了 FOR/FOREACH(和 WHILE)之外,还有更快的方法/方法/构造来迭代数组吗?
PHP 版本 5.3.0
回答在人们的帮助下,我能够拼凑出所有问题的答案.我将在这里总结它们:
PHP Version 5.3.0
Answer With help from people here I was able to piece together the answers to all question. I'll summarize them here:
- 我做错了什么吗?" 共识似乎是:是的,我不能在基准测试中使用 echo.就个人而言,我仍然看不到 echo 是如何具有随机执行时间的某个函数,或者任何其他函数有何不同——而且该脚本生成与 foreach 完全相同的结果的能力比一切都好虽然只是解释你正在使用回声"(我应该一直使用什么).但是,我承认测试应该用更好的方法来完成.虽然没有想到一个理想的折衷方案.
- PHP foreach 引用的东西真的有影响吗?我的意思是如果你通过引用它为什么不复制它?" ircmaxell 表明是的,进一步的测试似乎在大多数情况下证明了案例参考应该更快——尽管给出了我上面的代码片段,但绝对不是全部.我接受这个问题可能太不直观,无法在这样的级别上烦恼,并且需要一些极端的东西,例如反编译才能实际确定哪种情况更适合每种情况.
- "foreach 语句的等效迭代器代码是什么;我在网上看到了一些,但每次测试它们的时间都差了;我还测试了一些简单的迭代器构造,但从来没有似乎得到了甚至不错的结果——PHP 中的数组迭代器真的很糟糕吗?" ircmaxell 在下面给出了答案;虽然代码可能只对 PHP 版本 >= 5 有效
- 除了 FOR/FOREACH(和 WHILE)之外,还有更快的方法/方法/构造来迭代数组吗?" 感谢 Gordon 的回答.在 PHP5 中使用新的数据类型应该可以提高性能或提高内存(根据您的情况,这两者都可能是可取的).虽然在速度方面很多新类型的数组似乎并不比 array() 好,但 splpriorityqueue 和 splobjectstorage 似乎确实要快得多.戈登提供的链接:http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/
- "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.
- "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.
- "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
- "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.
对于任何简单的遍历,我可能会坚持使用 foreach(非参考版本).
I'll likely stick to foreach (the non-reference version) for any simple traversal.
推荐答案
我个人的意见是在上下文中使用有意义的东西.就我个人而言,我几乎从不使用 for
进行数组遍历.我将它用于其他类型的迭代,但 foreach
实在是太简单了……在大多数情况下,时间差会很小.
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.
需要注意的是:
for ($i = 0; $i < count($array); $i++) {
这是一个昂贵的循环,因为它每次迭代都会调用 count .只要你不这样做,我认为这并不重要......
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...
至于引用有所不同,PHP 使用写时复制,因此如果不写入数组,循环时的开销相对较小.但是,如果您开始修改数组中的数组,那么您将开始看到它们之间的差异(因为需要复制整个数组,并且引用可以只修改内联)...
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)...
对于迭代器,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();
}
至于是否有更快的迭代方法,这实际上取决于问题.但我真的需要问,为什么?我理解想要提高效率,但我认为你在浪费时间进行微优化.请记住,过早的优化是万恶之源
...
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
...
根据评论,我决定进行快速基准测试...
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
";
$start = microtime(true);
foreach ($a as $k => &$v) {
$v = $v + 1;
}
echo "Completed in ", microtime(true) - $start, " Seconds
";
$start = microtime(true);
foreach ($a as $k => $v) {}
echo "Completed in ", microtime(true) - $start, " Seconds
";
$start = microtime(true);
foreach ($a as $k => &$v) {}
echo "Completed in ", microtime(true) - $start, " Seconds
";
结果:
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...
仅引用的开销实际上比复制数组要少(这是在 5.3.2 上)...所以看起来(至少在 5.3.2 上)好像引用明显更快...
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...
使用 PHP 8.0 我得到以下结果:
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.
相关文章