массивы — как это возможно, в то время как & amp; список & amp; каждая комбинация намного быстрее, чем array_walk и foreach на PHP?

Я получил этот код:

<?php
// Test results
$array1 = test('array_walk');
$array2 = test('array_walk_list_each');
$array3 = test('array_walk_foreach1');
$array4 = test('array_walk_foreach2');

// Check arrays for equal
var_dump($array1 == $array2, $array1 == $array3, $array1 == $array4);

// Test function 1
function array_walk_list_each(&$array, $function, $userData = null) {
while ( list($key, $value) = each($array) )
$function($array[$key], $key, $userData);
}

// Test function 2
function array_walk_foreach1(&$array, $function, $userData = null) {
foreach ($array as $key => &$value )
$function($value, $key, $userData);
}

// Test function 3
function array_walk_foreach2(&$array, $function, $userData = null) {
foreach ($array as $key => $value )
$function($array[$key], $key, $userData);
}

function some_function(&$value, $key, $userData) {
$value = "$key => $userData";
}

function test($function, $count = 10000, $arrayElements = 1000) {
echo $function, ' ... ';
$array = array_fill(0, $arrayElements, "some text value");

$timer = microtime(true);
for( $i = 0; ++$i < $count; )
$function($array, 'some_function', 'some user data');
printf("%.3f sec\n", microtime(true) - $timer);

return $array;
}

Вывод из этого мне очень сложно понять:

array_walk ... 1.024 sec
array_walk_list_each ... 0.002 sec
array_walk_foreach1 ... 1.135 sec
array_walk_foreach2 ... 1.359 sec
bool(true)
bool(true)
bool(true)

разница в производительности между этими функциями это почти шутка.

Как это возможно? Я делаю что-то неправильно?

Я запускаю скрипт из терминала, используя PHP 7.0

3

Решение

Просто потому что each() необходимо сбросить массив, чтобы повторить его снова. Таким образом, у вас есть одно выполнение внутри функции цикла. Пока остальные перебирают это.

http://php.net/manual/en/function.each.php

Ваш результат будет производить только 1 итерацию из 10000 строк, а остальные будут 10000 итераций по 10000 строк.

$array = array_fill(0, 10000, uniqid('', false));
$fill = [];
$fill2 = [];
$timer = microtime(true);
for ($i = 0; $i < 10; $i++) {
while (list($key, $value) = each($array)) {
$fill[] = 'value';
}
}
printf("While list each %.3f sec\n", microtime(true) - $timer);
$timer = microtime(true);
for ($i = 0; $i < 10; $i++) {
foreach ($array as $key => $value) {
$fill2[] = 'value';
}
}
printf("Foreach %.3f sec\n", microtime(true) - $timer);
var_dump(count($fill), count($fill2));

Результат: https://3v4l.org/bvNdO


Чтобы получить одинаковые результаты для всех функций, вам необходимо изменить array_walk_list_each функция.

 while ( list($key, $value) = each($array) ){
$function($array[$key], $key, $userData);
}
reset($array);
2

Другие решения

foreach сбрасывает внутренний указатель массива перед каждым запуском и перемещает его вперед на каждом шаге. Это означает, что ваша тестовая функция будет называться 10 000 000, как вы, вероятно, ожидаете. Обход массива вообще не использует внутренний указатель, но все равно обрабатывает каждый элемент при каждом вызове. Вот почему время сопоставимо.

Но каждый из них просто увеличивает внутренний указатель после каждого использования. Он никогда не сбрасывает его (Google руководство для получения дополнительной информации). Это означает, что вы изменяете массив только один раз и никогда не входите в цикл while при последующих запусках. Так как ваша some_function является идемпотентом, вы проверяете на равные проходы, но время намного короче.

Изменить, чтобы добавить: сброс не должен быть явным. Рассмотрим этот код:

function array_walk_list_each_copy(&$array, $function, $userData = null) {
$a = $array;
while ( list($key, $value) = each($a) )
$function($array[$key], $key, $userData);
}

Каждый из них работает с копией массива каждый раз и изменяет внутренний указатель копии, а не оригинал. Он не побьет другие функции, но будет еще медленнее из-за накладных расходов на копирование при записи

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector