Архивы для категирии - ‘Оптимизация’

Оптимизация PHP

Профилирование кода

Если скорость выполнения кода неудовлетворительна, то первым делом необходимо его профилировать и измерить время, которое сценарий тратит на
выполнение различных задач и функций. На основе этой информации можно выяснить, на что сценарий расходует больше всего времени. Эти функции
называются узкими местами (bottlenecks).
Профилирование может преподнести сюрпризы. Например, может оказаться, что 99% времени сценарий тратит на запросы к базе данных, либо выявятся другие узкие места, такие как дисковый ввод/вывод при чтении больших файлов или журналов. Оптимизация не может быть эффективной без предварительного профилирования.

Как профилировать сценарии РНР
Для того чтобы профилировать сценарий РНР, надо снабдить таймерами некоторые функции и задачи сценария и измерить продолжительность их выполнения.
Допустим, есть такой сценарий РНР:
<?php
// Some initializations
require_once(»some_class.php»);
$foo = new some_class();
$res1 = $foo->do_a_method();
$res2 = $foo->do_a_method2();
echo($res1);
echo($res2);
?>

Если эффективность этого сценария недостаточна, то подозрение может пасть на три объекта, первым из которых оказывается конструктор some_class( ), вызываемый при создании объекта $foo.
Второй и третий подозреваемые – два вызываемых метода. Весь сценарий выполняется 2,3 секунды, и надо определить, как это время распределяется между тремя подозреваемыми.
Некоторое подозрение падает еще на четвертого, – как долго выполняется
require_once(), когда some_class() включает много методов. В интересах задач, обсуждаемых в этой главе, предположим, что вызов require_once( ) отнимает незначительную часть из 2,3 секунды времени выполнения сценария.
В РНР есть функция time(), возвращающая количество секунд, истекших с 1970 года. Однако она едва ли нам поможет, поскольку сценарии, в большинстве своем, выполняются менее чем за секунду, а если время выполнения сценария измеряется секундами, нужна намного большая точность, чтобы понять, на что тратится время. Точность эту обеспечивает функция microtime.

Функция microtime
Эта функция возвращает строку вида msec sec, где msec представляет составляющую в микросекундах, a sec – количество секунд после 1970 года, например:

<?php
echo(microtimeO);
?>

Результат может быть таким: 0.15672253 987612546
Это не очень удобно для вычисления разницы во времени, поэтому результат можно обработать так:
<?php
$time_portions = explode( ‘ ‘, microtimeO);
$actual_time = $titne_portions[1] . substr($time_portions[0], 1);
echo($actual_time);

С помощью этого кода преобразуем 0.15672253 987612546 в 987612546.15672253
Теперь надо получить эти числа перед выполнением функции или участка кода и после и найти разность между ними. Для получения разности с достаточной точностью служит функция bc_sub():

<?php
$elapsect_time = bcsub($end_time, $start_time, 6);
Для выполнения этого сценария расширение bcmath надо скомпилировать с РНР с помощью параметра –enable-bc-math.
Здесь 6 указывает количество десятичных знаков, которое надо сохранить в результате.
Создание класса Timer.
Заводить класс таймера при наличии средства профилирования РНР необязательно.
Этот класс поддерживает множественные таймеры. Далее описываются его основные функции:
timerStart().
Запускаем новый таймер или оставляем его как таймер по умолчанию.
Чтобы запустить таймер с определенным именем, вызываем timer_start(’foo’).
timerStop()
Останавливает заданный таймер или таймер по умолчанию, если имя не задано. Возвращает истекшее время работы таймера.
<?php
class Timer
var $timers = array();
function Timer() ;
// Nothing
function timerStart($name = ‘default’)
$time_portions = explode(’ ‘, microtime());
$actual_time =, $time_portions[1] . substr($time_portions[0], 1);
$this->timers['$name'] = $actual_time;
function timerStop($name = ‘default’)
$time_portions = explode(’ ‘, microtime());
$actual_time = $time_portions[1].substr($time_portipns[0], 1);
$elapsed_time = bcsub($actual_time, $this->timers['$name.'],6);
}
}
return $elapsed_time;
?>
Класс Timer вычитает одно время из другого с помощью функции bcsub( ), гарантирующей применения арифметики с повышенной точностью.
Сообщение error_message(undefined function bcsub ….. ) означает, что функции bcmath не были скомпилированы с РНР. Добавьте -enable-bcmath в строку
конфигурации, перекомпилируйте РНР и попытайтесь выполнить сценарий снова.
Мы проверили основу работы класса таймера. Еще один класс таймера входит в состав PEAR в файле pear/Benchmark/Timer. php дистрибутива РНР.
Класс PEAR отличается большей полнотой и сложностью.
Напишем другой класс – Time_Info, показывающий время, затраченное на выполнение функции phpinfo() и функции multiply(), умножающей большие числа:
<?php
// Этот тестовый класс показывает время, затраченное на выполнение функции,
// содержащей phpinfo(), и другой функции, перемножающей большие числа.
class Time_Info
{
// Конструктор
function Time_Info(){}
// Метод 1: содержит встроенную функцию phpinfoO
function phpinf()
{
phpinfo();
}
// Метод 2: перемножение больших чисел
function multiply()
{
$multiplied=10000*10000*10000*10000;
}
}
?>
Напишем теперь более сложный сценарий, основываясь на приведенном примере. Окружим каждый подозреваемый участок кода вызовами timer Start() и timerStop(), чтобы измерить время выполнения фрагментов:
<?php
// Инициализация
require_once(»Timer. php»);
require_once( «Time_Info.php» );
$tim = new Tlmer();
$tim->timerStart( ‘total’);
$tim->timerStart();
$foo = new Time_Info();
print(»Constructor: » . $tim->timerStop(). «<br>» );
$tim->titnerStart();
$res1 = .$foo->phpinf();
print(»Method1: » . $tim->timerStop(). «<br>» );
$tim->timerStart();
$res2 = $foo->multiply();
print(»Method2: » . $tim->timerStop(). «<br>» );
echo($res1);
echo($res2);
print( «Total execution time: » , $tim->tinierStop( ‘ total’) . «<br>»);
?>
Посмотрим, сколько времени заняли конструктор, php_inf() и multiply(), а также общее время выполнения сценария:
Constructor: 0.000084
Method1: 0.037100
Method2: 0.000101
Total execution time: 0.037980
Прогнав этот тест несколько раз, мы получим всю информацию, необходимую, чтобы узнать, которая из трех функций нуждается в оптимизации.
Итак, мы создали профиль для сценария.
Классификация узких мест
Профилирование осуществляется для поиска узких мест, а когда они обнаружены, их следует классифицировать по нескольким параметрам. Во-первых, надо оценить степень серьезности каждого узкого места. Во-вторых, следует оценить сложность оптимизации каждого из них. С учетом этих факторов принимается решение о том, какие функции, участки кода или методы сценария должны быть оптимизированы.

Оптимизация сценариев на php

Оптимизация
«Преждевременная оптимизация – корень всех зол».
Дональд Кнут «Искусство программирования»
данная статья взята из книги «Профессиональное программирование на PHP, авторы LArgerich, W.Choi, J.Coggeshall, и другие

Иногда, написав приложение веб-сайта на РНР, разработчики обнаруживают, что это приложение работает недостаточно быстро. Поэтому приходится оптимизировать код, чтобы сократить время выполнения сценариев. Несмотря нато что РНР, в целом, быстрый язык выполнения сценариев, существует ряд
технологий, рекомендаций и приемов, позволяющих оптимизировать код.

Выбор правильного языка
Первый вопрос, который возникает, когда производительность приложения оказывается неудовлетворительной, — это правильно ли выбран язык программирования. Возможно, медлительность обусловлена интерпретатором языка, и тогда нет смысла оптимизировать код – лучших результатов это не даст. Проводилось тестирование нескольких языков программирования, чтобысравнить их быстродействие с РНР. Измерения проводились по многим различным типам сценариев, включающих различные операции; результаты представляют собой усреднение величин, полученных во всех тестах.
Тестировались следующие языки:
• Сценарии CGI Perl
Обычный способ написания кода для веб-сайтов и приложений 1-2 года назад
Выбор правильного языка 913
• Сценарии FastCGI Perl
Механизм повышения производительности сценариев CGI
• Сценарии Python CGI
Использование Python для написания сценариев CGI
• Сценарии mod_python Python
Модуль Apache, позволяющий ему выполнять код Python, не обращаясь
к интерпретатору Python
• Сценарии С CGI
Компилированные сценарии С, выполняющиеся как программы CGI
• Сценарии mod_perl Perl
Модуль Apache, позволяющий выполнять сценарии Perl без вызова интерпретатора Perl
• PHP
Для сравнения те же сценарии программировались на РНР и выполнялись. После нескольких оценок производительности, включающих различные типы сценариев и загрузки серверов, был сделан вывод, что mod_perl, FastCGi и РНР дают самые быстрые результаты, мало различаясь между собой. Таким образом, если сайт или сценарий РНР работают медленно, то надо анализировать код, а не менять язык.

Оптимизация кода РНР

Говоря о задачах предварительной оптимизации (preoptimization), программисты рассуждают так: «Я заменю этот вектор хеш-таблицей и повышу скорость» или «Я заменю эту функцию ereg() несколькими функциями str_rep1асе(), это, повысит скорость». Они весьма заблуждаются. Во-первых, при такого рода оптимизации время выполнения сценария
обычно сокращается не более чем на 0,01 секунды, а потому польза невелика, зато легкость чтения кода может значительно пострадать. Во-вторых, предварительная оптимизация очень часто является непроизводительной тратой драгоценного времени программиста. Оптимизацией стоит заниматься, только убедившись в действительной ее необходимости. Профессиональным подходом к повышению производительности будет следующий:
• Профилировать код и найти узкие места
• Классифицировать узкие места
• Ликвидировать узкие места, оптимизировав код

Профилирование кода

Если скорость выполнения кода неудовлетворительна, то первым делом необходимо его профилировать и измерить время, которое сценарий тратит на выполнение различных задач и функций. На основе этой информации можно выяснить, на что сценарий расходует больше всего времени. Эти функции называются узкими местами (bottlenecks). Профилирование может преподнести сюрпризы. Например, может оказаться, что 99% времени сценарий тратит на запросы к базе данных, либо выявятся другие узкие места, такие как дисковый ввод/вывод при чтении больших файлов или журналов. Оптимизация не может быть эффективной без предварительного профилирования. Для того чтобы профилировать сценарий РНР, надо снабдить таймерами некоторые функции и задачи сценария и измерить продолжительность их выполнения.

Классификация узких мест


Профилирование осуществляется для поиска узких мест, а когда они обнаружены, их следует классифицировать по нескольким параметрам. Во-первых, надо оценить степень серьезности каждого узкого места. Во-вторых, следует оценить сложность оптимизации каждого из них. С учетом этих факторов принимается решение о том, какие функции, участки кода или методы сценария должны быть оптимизированы.

Техника оптимизации
Рассмотрим теперь различные способы оптимизации времени выполнения сценария в зависимости от происхождения узкого места:
• Оптимизация кода
Можно оптимизировать время выполнения интенсивных вычислений (плохо построенные циклы for() или while() или просто медленные команды).
• Буферизация и сжатие вывода
Этот прием полезен, если фактором замедления является сложность вывода в броузер, когда выводимо содержимое генерируется множеством функций.
• Оптимизация базы данных
Применяется, когда замедление обусловлено выполнением запросов к базе данных или интенсивным использованием соединений и функций баз данных.
• Кэширование
Применяется, когда замедление обусловлено временем генерации страницы, которое не может быть сокращено, либо запросы к базе данных невозможно оптимизировать. Другим основанием для кэширования может быть частое обращение к относительно статичным данным.

Продолжение следует…

Вы просматриваете архивы для Оптимизация категории.