Silent
Новичок
Эффективная работа с массивами в ПХП
Ниже приведены некоторые результаты работы ПХП кода с большими объемами данных. Под большим объемом можно понимать как однократную обработку одной строки, так и многократную обработку нескольких маленьких строк. Рассмотрим оба случая. В качестве теста решалась такая задача: дан текст (примем, что текст уже обработан, вырезаны все ненужные символы, слова отделены одним пробелом), нужно получить список уникальных слов. Измерения проводились на локальном компьютере (Athlon 1.4, WinME), версия ПХП - 4.1.0 и 4.2.3 (надо отметить, что новая версия гораздо быстрее старой). Использовались строки разной длины - 10, 150 и 500 килобайт. Данные строки обрабатывались в цикле несколько раз. Результаты приведены в следующем виде: тестируемый код, затем в первом столбце длина строки, во втором - число повторов, в третьем - время для старой версии, в четвертом - время для новой версии. При однократных повторах делалось несколько замеров, но все равно ошибка там может быть достаточно большая.
1) Самый очевидный код:
Короткие строки обрабатываются достаточно быстро в обоих версиях. С увеличением длины строки время растет очень нелинейно, особенно это заметно у старой версии, в новой дело обстоит лучше. При обработке больших строк в цикле у старой версии время также растет далеко не линейно, очевидно имеются большие накладные расходы на создание и уничтожение больших массивов. Новая версия показывает идеальное линейное приращение времени - 1, 5 и 50 секунд на 1, 5 и 50 повторов.
2) Небольшое изменение кода приводит к странным результатам.
Если для маленьких и средних строк почти ничего не изменилось, то для большой строки введение временного массива дало значительное ускорение.
3) Откажемся от встроенной функции array_unique и применим классический прием, популярный в Перле.
Опять для маленьких строк ничего не изменилось. Для средних и больших строк при многократном повторении кода новая версия невероятно быстрее старой. В среднем результаты быстрее, чем при использовании встроенной функции. Возникает вопрос, как же нужно програмировать, чтобы код на ПХП был быстрее "оптимизированной" функции на Си.
4) Наболее радикальный, почти сишный код:
При однократном выполнении кода он оказывается медленнее предыдущих (хотя и незначительно), но в цикле он обходит практически все остальные варианты. Единственной причиной этого явления может быть то, что в этом коде мы практически отказались от использования массивов (используется всего один массив). Отсюда вывод - для наиболее эффективной работы с массивами лучше всего по возможности отказаться от них. Лень было проводить дальнейшие замеры, но точно также не стоит использовать такие встроенные функции, как array_diff или array_intersect, их легко заменить парой строк на ПХП, как это было сделано в варианте 3.
Ниже приведены некоторые результаты работы ПХП кода с большими объемами данных. Под большим объемом можно понимать как однократную обработку одной строки, так и многократную обработку нескольких маленьких строк. Рассмотрим оба случая. В качестве теста решалась такая задача: дан текст (примем, что текст уже обработан, вырезаны все ненужные символы, слова отделены одним пробелом), нужно получить список уникальных слов. Измерения проводились на локальном компьютере (Athlon 1.4, WinME), версия ПХП - 4.1.0 и 4.2.3 (надо отметить, что новая версия гораздо быстрее старой). Использовались строки разной длины - 10, 150 и 500 килобайт. Данные строки обрабатывались в цикле несколько раз. Результаты приведены в следующем виде: тестируемый код, затем в первом столбце длина строки, во втором - число повторов, в третьем - время для старой версии, в четвертом - время для новой версии. При однократных повторах делалось несколько замеров, но все равно ошибка там может быть достаточно большая.
1) Самый очевидный код:
PHP:
$words = array();
$words = preg_split("/ /",$html_text);
$words = array_unique($words);
10kb - 500 раз - 2.7 sek. (3 sek)
150kb - 1 раз - 4.3 sek. (1 sek)
150kb - 5 раз - 73 sek. (5 sek)
150kb - 50 раз - - (50 sek)
500kb - 1 раз - 208 sek. (93 sek)
2) Небольшое изменение кода приводит к странным результатам.
PHP:
$words_temp = array();
$words = array();
$words_temp = preg_split("/ /",$html_text);
$words = array_unique($words_temp);
10kb - 500 раз - 2.7 sek. (3 sek)
150kb - 1 раз - 0.5 sek. (0.35 sek)
150kb - 5 раз - 60 sek. (4.4 sek)
150kb - 50 раз - - (49 sek)
500kb - 1 раз - 29 sek. (29 sek)
500kb - 5 раз - - (>5 min.)
3) Откажемся от встроенной функции array_unique и применим классический прием, популярный в Перле.
PHP:
$words_temp = array();
$words = array();
$words_temp = preg_split("/ /",$html_text);
foreach ($words_temp as $word) {
$words[$word] = 1;
}
10kb - 500 раз - 2.1 sek. (2.5 sek)
150kb - 1 раз - 0.064 sek. (0.065 sek)
150kb - 5 раз - 60 sek. (1.6 sek)
150kb - 50 раз - - (14.4 sek)
500kb - 1 раз - 0.9 sek. (0.8 sek)
500kb - 5 раз - >5 min. (16.7 sek)
4) Наболее радикальный, почти сишный код:
PHP:
$pos = 0;
$words = array();
do {
$new_pos = strpos($html_text," ",$pos);
if ($new_pos === FALSE) {
$word = substr($html_text,$pos);
$words[$word] = 1;
break;
};
$word = substr($html_text,$pos,$new_pos-$pos);
$words[$word] = 1;
$pos = $new_pos+1;
} while (1>0);
10kb - 500 раз - 3.4 sek. (3.5 sek)
150kb - 1 раз - 0.1 sek. (0.1 sek)
150kb - 5 раз - 1 sek. (1 sek)
150kb - 50 раз - 4.9 sek. (5.5 sek)
500kb - 1 раз - 1 sek (1 sek)
500kb - 5 раз - 10.6 sek. (3.5 sek)