Подкинули интересные данные результатов теста
Согласно этих тестов PHP очерь долго работает.
Я повторил на своей машине тест и получил вот такие данные
После у меня возникла идея переписать с ООП на функциональный подход, молучился вот такой код
function value($value){
if($value <= 2)
return 1;
$f1 = value($value - 1);
$f2 = value($value - 2);
return $f1 + $f2;
}
$x = value (40);
echo $x;
и вот такой вот результат теста
Вот и подумалось, что отказ от ипользования ООП php в Drupal имеет однако очень даже численное подтверждение разумности данного подхода.
Функции то работают быстрее.
Комментарии
Дадада
Некоторые путают скорость своего мышления и скорость Друпала, а потом говорят что Друпал тормозит потому что не ООП.
Интересны бы были также результаты с eAccelerator
102334155
real 20m46.089s
user 15m44.416s
sys 4m48.081s
!>
time php test2.php
102334155
real 2m22.887s
user 2m14.600s
sys 0m0.662s
тоесть практически никак, но собсно и не удивительно я этого ожидал.
От него есть существенная помошь, при "интрепетации" кода в опкод, и дальнейшее использование опкда без интрепетации.
А оптимизировать сам опкод тут как бы даже нечего - слишком простой .
вы наверное имели ввиду процедурный подход. пхп - не функциональный язык.
что, теперь предлагаете переписать друпал, чтоб везде
использовал рекурсию?
попробуйте еще, value(40000000);
у пхп жесткие ограничения на вложеность рекурсии.
ваш ответ совершенно не вкасу, плохое утро?
http://balancer.ru/tech/forum/2008/04/t61388--PHP-uskoryaem-programmy,me...
Вот еще интересная темка касательно производительности регекспов и строчных функций оттуда же, я думал, что последние быстрее, а оказывается(по наблюдениям автора поста) - наоборот! А в коде друпала очень много используется строковых функций, интересно, если их заменить на регекспы, будет ли прирост производительности и стоит ли обчинка вычинки?
Видимо ПХП рассматривает каждый вызов метода класса как виртуальный, и вычисляет реальное его месторасположение во время исполнения кода. Нечто подобное проходила в свое время Java, в Java Tiger джаст-ин-тайм умеет понять что у класса нет наследников и метод локейшн может вычислить всего один раз. Или что обьект создается в итерации и дальше нне используется по этому нет смысла напрягать мемори манагер и строить обьект для каждой итерации. С другой стороны, если у класса нет наследников то спрашивается зачем тогда писать такой класс, ООП кроме инкапсуляции ценен в первую очередь полиморфизмом. Вобщем тест на мой взгляд надуманный, со временем в ПХП появится какой то джаст-ин-тайм с мощными опциями оптимизации, даже если сейчас переписать задачку с которой ООП справляется на ура с использованием обычных функций - я думаю выигрыша не будет, не важно кто будет вычислять метод локейшн, в любом случае это будет происходить.
Переделал класс без избыточного использования памяти, производительность аналогичная производительности с применением функций:
{
function value($val)
{
if($val <= 2)
return 1;
$f1 = $this->value($val - 1);
$f2 = $this->value($val - 2);
return $f1 + $f2;
}
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$x = new Fib();
echo $x->value(30)."\n";
echo "<br>";
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Как видим, предположения мои не подтвердились и ПХП таки умеет оптимально вычислять метод локейшн, а полученный overkill как обычно нерациональное использование памяти.
Переделал тест на call_user_func, производительность ухудшилась ~ в два раза. На мой взгляд затраты терпимые, учитывая то что количество вызовов при простроении контента страницы не такое огромное.
if($value <= 2)
return 1;
$f1 = call_user_func("value",$value - 1);
$f2 = call_user_func("value",$value - 2);
return $f1 + $f2;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$x = call_user_func("value", 30);
//$x = value (30);
echo $x;
echo "<br>";
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Еще интересно было бы провести тесты по оптимизации строчных операций, подозреваю что оптимизация строчных операций может существенно прибавить в производительности ПХП.
результаты тестов на сервере
Intel(R) Core(TM)2 CPU 6400 @ 2.13GHz
PHP 5.2.8 (cli) (built: Jan 21 2009 22:31:29)
Copyright (c) 1997-2008 The PHP Group
Zend Engine v2.2.0, Copyright (c) 1998-2008 Zend Technologies
with eAccelerator v0.9.5.3, Copyright (c) 2004-2006 eAccelerator, by eAccelerator
with Zend Extension Manager v1.2.2, Copyright (c) 2003-2007, by Zend Technologies
with Zend Optimizer v3.3.3, Copyright (c) 1998-2007, by Zend Technologies
1)
832040
Monday 16th of February 2009 05:26:58 PM
real 0m1.176s
user 0m1.168s
sys 0m0.008s
2)
832040
Monday 16th of February 2009 05:27:43 PM
real 0m2.780s
user 0m2.744s
sys 0m0.014s
Вот еще один интересный тест по производительности string concatenations.
{
$str.="$i";
return;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$str = "";
for($i=0; $i < 100000; $i++)
{
getContent(&$str, $i);
}
echo $str;
echo "<br>";
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Производительность заметно ухудшится если поменять код следующим образом:
{
$str.="$i";
return $str;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$str = "";
for($i=0; $i < 100000; $i++)
{
$str = getContent(&$str, $i);
}
echo $str;
echo "<br>";
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Другим словами, операция:
Гораздо дешевле (в десятки раз!) чем:
В реальном ПХП приложении вторая ситуация встречается сплошь и рядом. В ПХП явно не хватает некоего класса StringBuilder, которая будет оптимизировать операции конкатенирования и копирования строк.
Например идея такая:
{
public $buf;
}
function getContent(StringBuilder $sb, $i)
{
$sb->buf .= "$i";
return $sb;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$sb = new StringBuilder();
for($i = 0; $i< 100000; $i++)
{
$sb = getContent($sb, $i);
}
echo $sb->buf;
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Понятно что это самая общая идея, основанная на том что объекты в ПХП передаются по ссылке, а не копируются. Можно добавить методы класса для манипуляции со строками, в результате получим объектноориентированную полнофункциональную строку которая будет передаваться по ссылке и будет оптимальна.
bratello, спасибо, интересно, а Вы не тестировали производительность регулярных выражений против производительности строк, тоже интересно было бы посмотреть.
Нет, не тестировал, кажется где то были эти тесты в сети. Важно решать реальные проблемы которые прибивают производительность в большинстве случаев, провести дополнительные тесты, как я понимаю вся проблема упирается в баннальный мемори менеджмент, строки и массивы передаются в функции копированием, а не по ссылке. Достаточно будет написать оптимизированные обёртки для строк и массивов, как ситуация изменится просто драмматическим образом, друпал (и не только) большую часть времени просто тупо копирует, о кешировании можно будет забыть! Берусь написать грамотные обертки, если соберется публика - можно сделать портинг ядра друпала и может пару центральных модулей на эти обертки, как минимум темизирование и рендеринг, посмотреть результаты, с тем чтобы предложить идею на drupal.org
Очень интересно продолжение, может отдельную тему поднять следует?
Запросто. Кстати, имплементация массивов в ПХП оказалась достаточно мощной, проделал вот такой тест:
{
protected $position = 0, $data = array();
public function rewind() {
$this->position = 0;
}
public function __construct()
{
}
public function current() {
$keys = array_keys($this->data);
return $this->data[$keys[$this->position]];
}
public function key() {
return $this->position;
}
public function next() {
++$this->position;
}
public function valid() {
return $this->position < $this->count();
}
//ArrayAccess members
public function offsetSet($offset, $value) {
$this->data[$offset] = $value;
}
public function offsetExists($offset) {
if( $this->count() > $offset )
return TRUE;
return FALSE;
}
public function offsetUnset($offset) {
unset($this->data[$offset]);
}
public function offsetGet($offset) {
if( !$this->offsetExists($offset) )
return NULL;
if( count($this->data) < $offset + 1)
$this->fetchAllData();
return $this->data[$offset];
}
public function count()
{
return count($this->data);
}
}
function getMyForm()
{
//$arr = new Form();
$arr["path1"] = array("aaa" => "bbb");
$arr["path2"] = array("aaa" => "bbb");
$arr["path3"] = array("aaa" => "bbb");
$arr["path4"] = array("aaa" => "bbb");
$arr["path5"] = array("aaa" => "bbb");
$arr["path6"] = array("aaa" => "bbb");
$arr["path7"] = array("aaa" => "bbb");
$arr["path8"] = array("aaa" => "bbb");
$arr["path9"] = array("aaa" => "bbb");
$arr["path10"] = array("aaa" => "bbb");
$arr["path11"] = array("aaa" => "bbb");
$arr["path12"] = array("aaa" => "bbb");
return $arr;
}
function renderForm($form)
{
$form["ggg"] = "hhhh";
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$forms = array();
for($i = 0; $i < 500; $i++)
{
$form = getMyForm();
for($j = 0; $j < 1000; $j++)
{
renderForm($form);
renderForm($form);
renderForm($form);
renderForm($form);
renderForm($form);
renderForm($form);
}
$forms[] = $form;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
Если разкоментировать первую строку в getMyForm, то получится что выигрыш минимальный, а при увеличении первой итерации и уменьшении второй итерации, массив явно выигрывает, сказывается слабая сторона аллокации объектов в ПХП. Видимо массивы реализованы хитрым способом copy on write, хотя и копирование тоже не происходит полностью. Вобщем все упирается в нормальную реализацию строковых операций, в моем тесте это разница в ~ 20 раз, даже если общий вклад строковых операций составляет одну треть, то общая производительность системы может увеличиться в два три раза. Кстати, аллокаторы памяти на разных платформах могут существенно различаться, интересно было бы все это прогнать на линухе, может оказаться что в других имплементациях ПХП на других платформах эта проблема решена. Нужно покопаться в исходниках ПХП интерпретатора.
Сделал дополнительные проверки со стрингами, судя по всему копирование там тоже хитрое, основная же проблема ПХП в реализации хипа памяти. В сорцах увидел реализацию ручного хипа, с кешированием, то есть сразу память не возвращается в систему, типа свой гарбич коллектор. Хип условно поделен на блоки маленького объема и блоки для большего объема, что в принципе разумно. Теперь не понятно почему пример со стринг билдером все таки работает значительно быстрее, если блок нужно с каждой итерацией увеличивать то будет периодическое реалоцирование.
{
public $buf;
}
function getContent(StringBuilder $sb, $i)
{
$sb->buf .= "$i";
return $sb;
}
echo date("l jS \of F Y h:i:s A");
echo "<br>";
$sb = new StringBuilder();
for($i = 0; $i< 100000; $i++)
{
$sb = getContent($sb, $i);
}
echo $sb->buf;
echo date("l jS \of F Y h:i:s A");
echo "<br>";
В интерпретаторе предусмотрен линт оптимайзер, дерево операций сводится к более простым формам, пока что не понял как его обмануть чтобы выяснить когда строка копируется реально...
Может на самом деле в ПХП есть средства, которые я ищу. К примеру, можно ли задать стратегию аллоцирования строк, сказать что строка которую я создаю имеет капасити 1к, и капасити инкремент тоже 1к, независимо от текущей длины строки, тогда количество реалокаций значительно сократится...
А у тебя на Линухе с оптимайзерами крутыми такая же ситуёвина? Может там все фикс?
Короче, нужно взять отладочную информацию для ПХП интерпретатора и прогнать тот же друпал на профайлере. Все эти тесты могут оказаться выгаданными проблемами, включая кстати тест с числом фибоначи. У каждого интерпретатора есть свои слабые места, но это не значит что все моторы спотыкаются именно об эти проблемные места...
Тесты для фибоначи(40) было бы не плохо для сравнения все таки получить... 30 я у себя в тесте на денвере использовал чтобы не выпадать по таймауту Но судя по всему результат будет как в первом посте - порядка 2-х минут, колбеки будут всего в два раза хуже, что на мой взгляд терпимо.
Давай я придумаю тесты для строк, интересно было бы с оптимизатором их прогнать... Строки, в ПХП строки важнее всего, впрочем это актуально для любого веб мотора, на любой платформе.
Проделал профайлинг друпала, не знаю насколько можно доверять профайлеру в PhpEd, тем не менее. Оказалось строки и колбеки и близко не стоят по своим затратам производительности, основное это include_once/required_once и ДБ. Тему можно торжественно закрывать, сон разума.