Циклы: 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); }}
использовать нельзя, т.к. от него будет немерянный буфер (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