Циклы: for, foreach, while, count/sizeof() - ускорение %-%
В начале программы создается массив $test из целых чисел (100 000 элементов). Потом один раз запускаются приведенные ниже примеры. Цикл проходит данный массив 3-мя способами (разными циклами) и выполняет кое-какие операции. Не выполнять в цикле ничего нельзя, ибо это будет уже совсем не реальный тест.
- {$x=0; foreach($test as $n) { $x=sprintf("test%08i",$i); }}
- {$x=0; for ($it=0; $it<100000; $it++) { $x=sprintf("test%08i",$i); }}
- {$x=0; $it=0; while($it<100000) { $x=sprintf("test%08i",$i); $it++; }}
- {$x=0; for ($it=0; $it<count($test); $it++) { $x=sprintf("test%08i",$i); }}
- {$x=0; $it=0; while($it<count($test)) { $x=sprintf("test%08i",$i); $it++; }}
- {$x=0; $co=count($test); for ($it=0; $it<$co; $it++) { $x=sprintf("test%08i",$i); }}
- {$x=0; $co=count($test); $it=0; while($it<$co) { $x=sprintf("test%08i",$i); $it++; }}
счетчик |
кол-во вызовов |
общее вpемя | сpеднее вpемя |
% от min | % от max | общее время |
test N1 | 1 | 12.0313 | 12.0313 | 154.4% | 100.0% | |
test N2 | 1 | 4.7290 | 4.7290 | 00.0% | 39.3% | | | test N3 | 1 | 4.7712 | 4.7712 | 00.9% | 39.7% | | | test N4 | 1 | 10.2847 | 10.2847 | 117.5% | 85.5% | | | test N5 | 1 | 10.3466 | 10.3466 | 118.8% | 86.0% | | | test N6 | 1 | 9.1271 | 9.1271 | 93.0% | 75.9% | | | test N7 | 1 | 9.1409 | 9.1409 | 93.3% | 76.0% | | |
Почему sprintf, а не реальное echo? echo
использовать нельзя, т.к. от него будет немерянный буфер (OUTPUT в браузер или консоль).
Теперь о деле. Бесспорный вывод - использование foreach сильно тормозит дело, а между for и while большой разницы нет. (На голом тесте for/while/foreach {..}
тормоза foreach - 30%). Это не удивительно, т.к. foreach делает копию массива, на что тратиться масса времени (хотя это только слухи).
Вывод с count()
не столь очевиден, потому что от разного текста в цикле % тормознутости от самого быстрого варианта резко возрастает... Я взял цикл с небольшой нагрузкой - проход по огромному массиву $test + форматирование функцией sprintf. Как видите, варинты с count() и заменяющей эту функцию перемнной $co различаются на 10% по скорости между собой (не смотрите на варинант с константой в 100000, заранее знать кол-во элементов невозможно).
Вывод о не ассоциативных массивах: 1) foreach существенно замедляет работу 2) использование count()
в простых циклах - замедленение 10%. Но на сложных циклах потери от лишних запусков count()
будут абсолютно незаметны, так что ситуация не очевидна.
Сравнение count() и sizeof().
Судя по мануалу - это алиасы. Об этом написано на страницах самих функций и дополнительной странице "Appendex => Aliases list". Что же мы видим на массиве в 100000 элементов:
- {$x=0; for ($it=0; $it<count($test); $it++) { $x=sprintf("test%08i",$test[$it]);}}
- {$x=0; for ($it=0; $it<sizeof($test); $it++) { $x=sprintf("test%08i",$test[$it]);}}
счетчик |
кол-во вызовов |
общее вpемя | сpеднее вpемя |
% от min | % от max | общее время | test N1 | 1 | 3.0087 | 3.0087 | 15.7% | 100.0% | |
test N2 | 1 | 2.5998 | 2.5998 | 00.0% | 86.4% | | |
Пусть тесты будут иметь погрешности... Но результат один - count() заметно отстает по скорости от sizeof()! Хм, я бы к записи в мануале сделал приписку: "The sizeof() function is an alias for count(), but последний сильно тормозит!"
Если кол-во элементов в массиве меньше 65000 (64К), то эти функции по скорости практически не различимы. Тут вывод простой - переходим на использование sizeof(), как ускоренного алиаса count(). Это принесет свои результаты на огромных массивах.
Ассоциативные массивы: тестирование разных способов перебора
С ними наблюдается таже проблема: на разных по величине массивах разные функции эффективны, но лучше всех foreach!
Массив в 200 элементов и 1000 повторов программы:
- {$x=0; foreach($test as $k=>$v) { $x=sprintf("%s=>%s\n",$k,$v); }}
- {$x=0; reset($test); while (list($k, $v) = each($test)) { $x=sprintf("%s=>%s\n",$k,$v); }}
- {$x=0; $k=array_keys($test); $co=sizeof($k); for ($it=0; $it<$co; $it++) { $x=sprintf("%s=>%s\n",$k[$it],$test[$k[$it]]); }}
- {$x=0; reset($test); while ($k=key($test)) { $x=sprintf("%s=>%s\n",$k,current($test)); next($test); }}
счетчик |
кол-во вызовов |
общее вpемя | сpеднее вpемя |
% от min | % от max | общее время | test N1 | 1 | 8.1222 | 8.1222 | 00.0% | 78.7% | |
test N2 | 1 | 10.3221 | 10.3221 | 27.1% | 100.0% | | | test N3 | 1 | 9.7921 | 9.7921 | 20.6% | 94.9% | | | test N4 | 1 | 8.9711 | 8.9711 | 10.5% | 86.9% | | |
Тоже самое, но массив в 5000 элементов и 200 повторов:
счетчик |
кол-во вызовов |
общее вpемя | сpеднее вpемя |
% от min | % от max | общее время | test N1 | 1 | 14.4473 | 14.4473 | 00.0% | 67.2% | |
test N2 | 1 | 18.6801 | 18.6801 | 29.3% | 86.9% | | | test N3 | 1 | 21.5056 | 21.5056 | 48.9% | 100.0% | | | test N4 | 1 | 15.8514 | 15.8514 | 09.7% | 73.7% | | |
Опять тоже самое, но массив в 100 000 элементов и без повторов:
счетчик |
кол-во вызовов |
общее вpемя | сpеднее вpемя |
% от min | % от max | общее время | test N1 | 1 | 3.5116 | 3.5116 | 00.0% | 82.8% | |
test N2 | 1 | 3.9724 | 3.9724 | 13.1% | 93.6% | | | test N3 | 1 | 4.2436 | 4.2436 | 20.8% | 100.0% | | | test N4 | 1 | 4.0026 | 4.0026 | 14.0% | 94.3% | | |
Другие тесты на холостых циклах тоже показывают преимущество foreach.
Резюме:
- sizeof() лучше, чем count()
- в циклах sizeof лучше вообще заменить на переменную
- for и while практически не отличимы
- для перебора простых индексных массивов нужно использовать for или while
- для перебора ассоциативных массивов нужно использотьва foreach
Содержание раздела
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|