Рейтинг@Mail.ru

PHP работа со строками, скорость и расход памяти при конкатенации

Практически большинство веб-мастеров так или иначе связаны с использованием PHP для создания и поддержки динамического контента сайтов и веб-сервисов. Естественно, что подавляющее количество контента веб-ресурсов генерируется PHP-скриптами с использованием конкатенации (слиянием, склеиванием) строк, используя для этого различные допустимые для PHP методы работы со строками. Однако не многие знают, какие же конструкции кода PHP для конкатенации строк предоставляют наилучшую скорость работы (производительность) скриптов и при этом наименьший расход памяти.
Скорость скрипта конкатенации строк

У каждого веб-мастера, как начинающего, так и продвинутого, есть свой стиль и предпочтения в написании кода PHP скриптов, но тем не менее практически все знают три популярные синтаксические конструкции для склеивания строки текста из нескольких частей:

$b = "Часть строки 2";
$c = "Часть строки 3";

// первая конструкция
$a = "Часть строки 1" . $b . $c;

// вторая конструкция
$a = "Часть строки 1" . "$b $c";

// третья конструкция
$a .= "Часть строки 1";
$a .= $b; 
$a .= $c;

Давайте протестируем, с какой же из приведенных выше синтаксических конструкций при выполнении PHP-скрипт покажет наилучшую производительность и сколько при этом он будет расходовать оперативной памяти.

Для тестов подготовлены скрипты, в каждом из которых будет использоваться конкретная синтаксическая конструкция конкатенации (склеивания) строк. Начальная строка, переменная $a, изначальна нулевая, но в цикле, состоящем из 10000 шагов ($steps = 10000;) к строке $a будут добавляться части текста "01234567890123456789", являющегося значениями переменных $b, $c и $d.

Работа тестовых скриптов проверена на четырех версиях PHP 5.2.17, 5.3.26, 5.4.16 и 5.5.0. Результат, как может показаться странным для некоторых, практически одинаков при выполнении конкретного теста на всех версиях PHP, хотя вроде бы еще для версии PHP 5.2.x был зарегистрирован баг, касающийся алгоритма работы движка со строками, но его так похоже и не исправили даже в самой последней версии PHP 5.5.0.

Первый тест

Начнем с проверки работы (скорости и расхода памяти) самой, как мне кажется, популярной конструкции для конкатенации (склеивании) строк типа
$a = $a . $b . $c . $d;

<?php

$steps = 10000;

unset($a,$b,$c,$d);

$b = "01234567890123456789";
$c = "01234567890123456789";
$d = "01234567890123456789";

$timer_start = microtime(1);

for($i=0;$i<$steps;$i++) {
    $a = $a . $b . $c . $d;
}

$timer_end = microtime(1);
$timer_result = $timer_end - $timer_start;
echo "Time = ".$timer_result." Seconds<br>";
echo "Peak memory usage = " , memory_get_peak_usage(true) , " Bytes <br>";
echo "String length = " , strlen($a) , " Chars<br><br>";

?>

Результат выполнения скрипта:

Time = 2.49258804321 Seconds
Peak memory usage = 2621440 Bytes
String length = 600000 Chars

Как Вы видите, время, затраченное на выполнение цикла из 10000 шагов, превышает 2 секунды и пиковый расход памяти равен 2,621,440 байт. Результат практически одинаков для всех версий PHP 5.2.x - 5.5.0

Второй тест

Теперь проверим скорость работы и расходуемую память другой конструкцией для конкатенации строк, где в строку вставляются значения переменных:
$a = $a . "$b $c $d";

Заметьте, что часть кода для формирования строки заключена именно в двойные кавычки, а не в одиночные. При использовании одиночных кавычек у нас бы просто к строке добавлялся текст из 8 символов '$b $c $d', а нам нужно, чтобы добавлялись конкретные текстовые значения переменных $b, $c и $d.

<?php

$steps = 10000;

unset($a,$b,$c,$d);

$b = "01234567890123456789";
$c = "01234567890123456789";
$d = "01234567890123456789";

$timer_start = microtime(1);

for($i=0;$i<$steps;$i++) {
    $a = $a . "$b $c $d";
}

$timer_end = microtime(1);
$timer_result = $timer_end - $timer_start;
echo "Time = ".$timer_result." Seconds<br>";
echo "Peak memory usage = " , memory_get_peak_usage(true) , " Bytes <br>";
echo "String length = " , strlen($a) , " Chars<br><br>";

?>

Результаты работы скрипта теперь существенно отличаются — время выполнения уменьшилось почти в три раза, да и расход памяти также уменьшился:

Time = 0.84291505813599 Seconds
Peak memory usage = 1835008 Bytes
String length = 620000 Chars

Это были результаты для версии PHP 5.4.16, а вот для PHP 5.5.0 все выглядит уже более радужно — скорость работы увеличилась на порядки, и дополнительно уменьшился расход памяти:

Time = 0.0049998760223389 Seconds
Peak memory usage = 1048576 Bytes
String length = 620000 Chars

Третий тест

Напоследок проверяем производительность работы и расход памяти при использовании конструкции для конкатенации строк типа

$a .= $b;
$a .= $c;
$a .= $d;

где мы также дополняем строку в переменной $a подстроками из значений переменных $b, $c и $d:

<?php

$steps = 10000;

unset($a,$b,$c,$d);

$b = "01234567890123456789";
$c = "01234567890123456789";
$d = "01234567890123456789";

$timer_start = microtime(1);

for($i=0;$i<$steps;$i++) {
	$a .= $b;
	$a .= $c;
	$a .= $d;
}

$timer_end = microtime(1);
$timer_result = $timer_end - $timer_start;
echo "Time = ".$timer_result." Seconds<br>";
echo "Peak memory usage = " , memory_get_peak_usage(true) , " Bytes <br>";
echo "String length = " , strlen($a) , " Chars<br><br>";

?>

В результате мы получаем абсолютно одинаковую, причем самую наилучшую производительность (скорость работы) скрипта для всех проверяемых нами версий PHP 5.2.17, 5.3.26, 5.4.16 и 5.5.0.

Time = 0.0049998760223389 Seconds
Peak memory usage = 1048576 Bytes
String length = 600000 Chars

Заключение

Для большей наглядности и сравнения привожу в пример все результаты тестов (за исключением второго теста, выполненного под PHP 5.5.0):

// конструкция $a = $a . $b . $c . $d;

Time = 2.49258804321 Seconds
Peak memory usage = 2621440 Bytes
String length = 600000 Chars

// конструкция $a = $a . "$b $c $d";

Time = 0.84291505813599 Seconds
Peak memory usage = 1835008 Bytes
String length = 620000 Chars

// конструкция $a .= $b; $a .= $c; $a .= $d;

Time = 0.0049998760223389 Seconds
Peak memory usage = 1048576 Bytes
String length = 600000 Chars

По результатам тестов видно, что самая высокая скорость работы (производительность) скрипта для конкатенации (склеивании) строк достигается конструкцией вида:

$a .= $b;
$a .= $c;
$a .= $d;

Причем эта синтаксическая конструкция одинаково хороша для всех популярных и новых версий PHP от 5.2.17 до 5.5.0. Конечно, такая конструкция для конкатенации строк занимает по нескольку строк кода, но ведь она дает именно положительный результат. Да и как мне кажется, такой вид записи кода наиболее понятен и легко читаем.

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

Удачных Вам решений!

Метки: PHP, память, скорость, строки

Поделитесь материалом с другими, воспользуйтесь этими кнопками:
Получать обновления и новые материалы блога по E-mail

2 комментария к “PHP работа со строками, скорость и расход памяти при конкатенации”

  1. Ермак:

    А как вы проверяли на разных версиях PHP? Я вот попробовал на одном из своих сайтов и даже при одном скрипте, например из первого теста, результаты по скорости прилично отличаются даже при проверке на PHP 5.2. Правда все равно слишком много по времени выполняется.

    • Я проверял на CentOS 6.4, там установлены все из перечисленных в статье версии PHP. Сервер локальный, не паблик. Если Вы для тестов использовали удаленный сайт, и к тому же на бюджетном хостинге (shared-хостинг например), то естественно, что результаты могут различаться при каждой проверке, т.к. Вы скорее всего не сможете контролировать состояние системы (занятость, загрузку процессора и доступность оперативной памяти).

      Для тестов я бы Вам посоветовал использовать либо виртуальную машину, либо на Windows установите OpenServer (open-server.ru) последней версии. В нем как раз есть все нужные версии PHP.

Оставить комментарий

Подписаться на обновления блога 4remind.ru по RSS
Новости блога в социальных сетях

Новости блога 4remind.ru в Твиттере Персональная страница блога 4remind.ru в Facebook Персональная страница блога 4remind.ru в Google+ Новостная лента блога 4remind.ru в FriendFeed

4remind.ru - персональный блог вебмастера

Rambler's Top100
Рейтинг@Mail.ru


Яндекс.Метрика