Статьи (например тут, тут), освещавшие этот вопрос о более ранних версиях, говорили, что обычные циклы с точки зрения производительности более выгодны.
А вот здесь можно уже увидеть тесты, для 7-ой версии. И то не все так в ней однозначно. В тестах от 19/11/2015 циклы и встроенные функции сравнялись по производительности, и только последний топик наводит нас на размышления.
А что же по итогу… Я решил все проверить самостоятельно и прогнать несколько тестов…
1) array_filter
$data = range(0, 10000);
$start = microtime(true);
$data = array_filter($data, function ($item) {
return $item%2;
});
$end = microtime(true);
echo $end - $start.' ';
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
foreach ($data as $item) {
if ($item%2) {
$newData[] = $item;
}
}
$end = microtime(true);
echo $end - $start.' ';
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
for($i=1;$i<=$numItems-1;$i++) {
if ($data[$i]%2) {
$newData[] = $data[$i];
}
}
$end = microtime(true);
echo $end - $start.' ';
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
$i = 0;
while ($i <= $numItems-1) {
if ($data[$i]%2) {
$newData[] = $data[$i];
}
$i++;
}
$end = microtime(true);
echo $end - $start.' ';
Округленно…
функция | PHP5 | PHP7 |
---|---|---|
array_filter | 0.00282 | 0.00136 |
foreach | 0.0013 | 0.00045 |
for | 0.00171 | 0.00072 |
while | 0.00145 | 0.00054 |
2) array_map
<?php
$data = range(0, 10000);
$start = microtime(true);
$data = array_map(function ($item) {
return $item+1;
}, $data);
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
foreach ($data as $item) {
$newData[] = $item+1;
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
for($i=0;$i<$numItems;$i++) {
$newData[] = $data[$i]+1;
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
$i = 0;
while ($i < $numItems) {
$newData[] = $data[$i];
$i++;
}
$end = microtime(true);
echo $end - $start;
функция | PHP5 | PHP7 |
---|---|---|
array_map | 0.00462 | 0.00094 |
foreach | 0.00155 | 0.00033 |
for | 0.00220 | 0.00044 |
while | 0.00169 | 0.00054 |
3) array_walk
$data = range(0, 10000);
$start = microtime(true);
$data = array_walk($data, function ($item) {
return $item+1;
});
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
foreach ($data as $item) {
$newData[] = $item+1;
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
for($i=0;$i<$numItems;$i++) {
$newData[] = $data[$i]+1;
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = array();
$numItems = count($data);
$i = 0;
while ($i < $numItems) {
$newData[] = $data[$i];
$i++;
}
$end = microtime(true);
echo $end - $start;
функция | PHP5 | PHP7 |
---|---|---|
array_walk | 0.00285 | 0.00101 |
foreach | 0.00290 | 0.00088 |
for | 0.00219 | 0.00043 |
while | 0.00173 | 0.00086 |
4) array_reduce
$data = range(0, 10000);
$start = microtime(true);
$data = array_reduce($data, function ($carry, $item) {
$carry += $item;
return $carry;
},0);
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = 0;
foreach ($data as $item) {
$newData+= $item;
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = 0;
$numItems = count($data);
for($i=0;$i<$numItems;$i++) {
$newData+= $data[$i];
}
$end = microtime(true);
echo $end - $start;
$data = range(0, 10000);
$start = microtime(true);
$newData = 0;
$numItems = count($data);
$i = 0;
while ($i < $numItems) {
$newData+= $data[$i];
$i++;
}
$end = microtime(true);
echo $end - $start;
функция | PHP5 | PHP7 |
---|---|---|
array_reduce | 0.00239 | 0.00092 |
foreach | 0.00044 | 0.00020 |
for | 0.00066 | 0.00029 |
while | 0.00062 | 0.00029 |
Понятно, что цифры относительны. Но некоторые выводы, уважаемые коллеги, сделать позволяют.
Комментарии (9)
Fesor
22.10.2017 21:28Но некоторые выводы, уважаемые коллеги, сделать позволяют.
например что делать подобным образом подобные микро-бенчмарки не очень-то хорошая идея. Есть замечательный инструмент для подобного: phpbench. Как минимум с точки зрения статистической погрешности будет чище.
Далее, какие выводы еще мы можем сделать… Да собственно никаких. Методика проведения измерений мягко скажем не дает вообще никаких данных о том какие выводы мы можем сделать. Да, циклы будут всегда быстрее (особенно foreach) чем array_* функции тупо за счет отсутствия необходимости делать вызов функции на каждую итерацию. Причем что то что то — константа и на объемах выборок менее скажем десятков миллионов нам в целом плевать какой из вариантов мы используем.
Позвольте привести мою версию вашего бенчмарка (мне лень потому возьму только
array_filter
:
РезультатыИсходник
<?php /** * @BeforeMethods({"init"}) */ class ArrayFilterBenchmark { public function init() { $this->data = range(1, 100000); } public function benchArrayFilter() { array_filter($this->data, function ($item) { return $item % 2; }); } public function benchForeach() { $data = $this->data; $newData = array(); foreach ($data as $item) { if ($item % 2) { $newData[] = $item; } } } }
Результаты
PhpBench 0.13.0. Running benchmarks. \ArrayFilterBenchmark benchArrayFilter I99 P0 [? Mo]/r: 7,321.920 7,036.505 (?s) [?SD ?RSD]/r: 576.149?s 7.87% benchForeach I99 P0 [? Mo]/r: 4,389.150 4,198.309 (?s) [?SD ?RSD]/r: 463.250?s 10.55% 2 subjects, 200 iterations, 2 revs, 0 rejects (best [mean mode] worst) = 3,947.000 [5,855.535 5,617.407] 6,370.000 (?s) ?T: 1,171,107.000?s ?SD/r 519.700?s ?RSD/r: 9.212%
Запускалось на MacBook Pro 15" 2017, без XDebug.
PHP 7.1.4 (cli) (built: May 6 2017 10:02:00) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies with Zend OPcache v7.1.4, Copyright (c) 1999-2017, by Zend Technologies
Gemorroj
23.10.2017 00:45проведите подобные тесты с помощью специализированного инструмента.
в ваших тестах, как минимум, ничего не сказано про потребляемую память и нет вариантов с разными данными в массивах.
ReinRaus
23.10.2017 12:21Есть подозрение, что Вы измеряли время, которое тратится на 10000 вызовов функции и возврат результата из этой функции. Попробуйте применить более «тяжелые» вычисления и это время станет незаметно в общем результате.
Nikolay_Smeh
Я думаю, что код не совсем верен. Замените в случае с array_ функциями $data на $newData, Вы увидите совершенно другие результаты.