Пора сделать закреплённый топик для эксперемнтов с PHP - бенчмарки, тесты на поведение и.т.д. Обсуждение только в тему тестов. Никаких вопросов "Зачем?", "Нафиг надо?" и.т.д. Не нравится - не читаем. Не забываем что можно постить нестандартные или нетривиальные решения. Они должны быть действительно одим из: а). Странное. б). Неочевидное или "недокументированная фича" в). Что-то достаточно сложное, что бы большая часть обитателей форума сломала мозг. В первом сообщении буду прописывать линки на очередные тесты в теме. * switch () { case } vs if ( || ) vs in_array() * проверить скорость перебора массива двумя способами. * sleep vs. usleep * что быстрей для выбора последней записи в таблице (100к) * http://www.php.ru/forum/viewtopic.php?p=161924#161924 * влияние длины переменных на скорость выполнения скрипта. * Подтверждение того, что preg_* работает быстрее ereg_* * Тестирование скорости вызова методов класса разными способами (2 поста, линк ведёт на 1-й) * Скорости работы прямого и обратного циклов (жесть однако ) * md5($string) vs hash('md5', $string) * Правда, что статика медленная? * Тестирование скорости работы запросов в MySQL на вставку и выборку данных в разных вариациях * Эффективное уменьшение изображений, или как можно сэкономить 400% времени. * Рекурсия vs цикл при вычисоении факториала - the epic fail!
Мои первые 5 копеек. Цель - проверить скорость работы switch () { case } vs if ( || ) vs in_array(). Код (PHP): <?php define('MAX', 1000000); echo 'SWITCH<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { switch ($v) { case 'blabla': case 'uhuhuh': break; case 'huhuhu': break; } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'IF'.'<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { if ($v == 'blabla' || $v == 'uhuhuh') { } else { } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'IF (look for less)'.'<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { if ($v == 'huhuhu') { } else { } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'IN_ARRAY'.'<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { if (in_array($v, array('blabla', 'uhuhuh'))) { } else { } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'IN_ARRAY (array initialised before)'.'<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); $arr = array('blabla', 'uhuhuh', 'huhuhu'); for ($i = 0; $i < MAX; ++$i) { if (in_array($v, $arr)) { } elseif ($v == 'huhuhu') { } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'---------- BONUS !!! --------'.'<br />'; echo 'BIG SWITCH<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { switch ($v) { case 'blabla': break; case 'awegfqwegqwerg': break; case 'aergqerghweth': break; case 'afa': break; case 'asdfsd': break; case 'asdf': break; case 'fwefwef': break; case 'adfgasdf': break; case 'asdf': break; case 'asdrt': break; case 'gqererqrwe': break; case '1': break; case 2: break; case 3: break; case 4: break; case 'uhuhuh': break; case 5: break; case 6: break; case 7: break; case 8: break; case 9: break; case 0: break; case 122: break; case 1234: break; case 241254: break; case 2345: break; case 234154: break; case 241234: break; case 1241234: break; case 124123423: break; case 41234: break; case 23: break; case 4123423: break; case 4: break; case 56: break; case 2: break; case 2: break; case 4: break; case 'huhuhu': break; } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } echo '<br />'.'<br />'.'BIG IN_ARRAY (array initialised before)'.'<br />'; foreach (array('blabla', 'uhuhuh', 'huhuhu') as $v) { $time = microtime(true); $arr = array('blabla', 'awegfqwegqwerg', 'aergqerghweth', 'afa', 'asdfsd', 'asdf', 'fwefwef', 'adfgasdf', 'asdf', 'asdrt', 'gqererqrwe', '1', 2,3,4,'uhuhuh',5,6,7,8,9,0,122,1234,241254,2345,234154,241234, 1241234,124123423,41234,23,4123423,4,56,2,2,4, 'huhuhu'); for ($i = 0; $i < MAX; ++$i) { if (in_array($v, $arr)) { } else { } } echo $v, ': '.number_format((microtime(true) - $time), 10, '.', '').'<br />'; } Результат: Код (Text): SWITCH blabla: 0.2071468830 uhuhuh: 0.3163371086 huhuhu: 0.3905041218 IF blabla: 0.2027728558 uhuhuh: 0.2863938808 huhuhu: 0.3096029758 IF (look for less) blabla: 0.1977119446 uhuhuh: 0.1971809864 huhuhu: 0.1936748028 IN_ARRAY blabla: 0.6297330856 uhuhuh: 0.6948361397 huhuhu: 0.6891119480 IN_ARRAY (array initialised before) blabla: 0.3601179123 uhuhuh: 0.4338660240 huhuhu: 0.5059688091 ---------- BONUS !!! -------- BIG SWITCH blabla: 0.2016208172 uhuhuh: 1.4647359848 huhuhu: 1.8207859993 BIG IN_ARRAY (array initialised before) blabla: 0.3605790138 uhuhuh: 1.4366469383 huhuhu: 1.7227311134 Отсюда выводы: 1). switch case тоже самое что if () elseif () elseif ..... else; Если не надо сравнивать слишком уж много значений - лучше if 2). Чем проще условие - тем быстрее. Лучше проверить на false, чем на true || true 3). in_array - это долго при малом кол-ве элементов 4). При большом кол-ве элементов если вам нужен один конкретный - проще сделать in_array - разница в скорости мизерная.
О! пост удалили. Впервые тут такое. Скоро бояться буду что- то написать. Вдруг забанят. так ты Важно: то убери, чтоб не моячило. Не позорь форум. Важно- это то что всем полезно и может пригодиться, а кружок извращенцев, где ты сам с собой общаешься на тему что быстрее foreach или inarray- это не важно.
alexey_baranov Подобных тем было уже не одна, и не две, и даже не 3 по разным исследованиям. Ну а немного юмора в заголовке не помешает самому топику. Тему зачистил потому, что hight попросил.
Цель: проверить скорость перебора массива двумя способами. Код (PHP): <?php set_time_limit(0); function timer() { static $mark = null; if ($mark === null) { $mark = microtime(0); } else { $res = microtime(0) - $mark; $mark = null; return substr($res, 0, 6); } } /** * Сравнение скорости перебора массива двумя способами способами: * циклом foreach и циклом while с функцией each. */ // Создаем массив с весом элементов 1Мб $array = array(); for ($i=0; $i<1000000; $i++) { $array[$i] = 1; } //Вариант первый timer(); foreach ($array as $k => $v) { $var = $v; } echo 'Вариант с foreach: '.timer().' сек<br>'; //Вариант второй: timer(); while (list($k, $v) = each($array)) { $var = $v; } echo 'Вариант с while each: '.timer().' сек<br>'; ?> средний результат: Вариант с foreach: 0.2438 сек Вариант с while each: 1.7000 сек[/list:u]
Попробуй ещё ради прикола Код (PHP): <? function _foreach($arr){ $var=current($arr); if(next($arr)){ _foreach($arr); } return; } ?>
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 35 bytes) in W:\host\whileeach.php on line 20 =)
Наибредовейшая задача: sleep vs. usleep Цель: выяснить, какя функция спит дольше, ну, или, точнее: Код (PHP): <?php set_time_limit(0); function timer() { static $mark = null; if ($mark === null) { $mark = microtime(1); } else { $res = microtime(1) - $mark; $mark = null; return substr($res, 0, 6); } } timer(); for ($i=0;$i<10;$i++) { sleep(1); } echo 'Sleep: '.timer().' cек<br>'; timer(); for ($i=0;$i<10;$i++) { usleep(1000000); } echo 'Usleep: '.timer().' сек'; ?> Полученые результаты: Sleep: 9.9896 cек Usleep: 10.000 сек[/list:u] Sleep: 9.9949 cек Usleep: 9.9971 сек[/list:u] Sleep: 9.9855 cек Usleep: 9.9999 сек[/list:u] Вывод: используйте usleep для повышения точности работы скрипта, и sleep - для ускорения работы скрипта :lol:
Решил выяснить, что же быстрей для выбора последней записи в таблице (100к): 1. Выбрать через ORDER BY DESC LIMIT 1 2. $var = MAX(id), SELECT WHERE id=$var 3. SELECT WHERE id = (SELECT MAX(id) Код (PHP): <?php for ($x = 1; $x <= 100000; $x++) { $start_t = microtime(true); $mysqli->query('SELECT SQL_NO_CACHE * FROM tst ORDERY BY `id` DESC LIMIT 1'); $times[] = microtime(true) - $start_t; } $t1 = array_sum($times) / 100000; echo $t1."\n"; unset($times); $times = array(); for ($x = 1; $x <= 100000; $x++) { $start_t = microtime(true); $id = $mysqli->query('SELECT SQL_NO_CACHE MAX(`id`) FROM tst')->fetch_array(); $mysqli->query('SELECT SQL_NO_CACHE * FROM tst WHERE `id`='.$id[0]); $times[] = microtime(true) - $start_t; } $t2 = array_sum($times) / 100000; echo $t2."\n"; echo $t2 - $t1."\n"."\n"; $times = array(); for ($x = 1; $x <= 100000; $x++) { $start_t = microtime(true); $mysqli->query('SELECT SQL_NO_CACHE * FROM tst WHERE `id`=(SELECT SQL_NO_CACHE MAX(`id`) FROM tst)'); $times[] = microtime(true) - $start_t; } $t3 = array_sum($times) / 100000; echo $t3."\n"; Результаты: Код (Text): №1: 0.0006240371465683 №2: 0.0018119875121117 №3. 0.001077238035202 №2 - №1: 0.0011879503655434 Вложенный запрос в этом варианте оказался быстрее, чем тот, что использует PHP. Интересно, в более сложных запросах тоже так? Командная строка php, WinXP, Amd Duron 1.6
Kreker Вобще-то самым быстрым оказался варант с ORDER BY LIMIT (я результаты в теги code оформил), причём быстрее сильно. Объяснить это на самом деле очень просто - PRIMARY KEY индекс упорядочен, так что MySQL просто посмотрел в его конец и выбрал данные.
Эксперименты с memory usage и serialize(). Цель: нужно было узнать насколько имеет смысл приводить данные к int/float при сериализации данных. Конкретно приминительно к memcache для снижения трафика. Код (PHP): <?php $test = array(); for ($i = 0; $i < 1000; ++$i) { $test[] = array('id' => 105, 'name' => 'Psihius', 'age' => 29, 'upd_time' => 1245076167, 'pht_id' => 16); } $memory = memory_get_usage(); $string = serialize($test); echo 'Memory: '.(memory_get_usage() - $memory).PHP_EOL; echo 'Strlen: '.strlen($string).PHP_EOL.PHP_EOL.PHP_EOL; unset($test, $string); $test = array(); for ($i = 0; $i < 1000; ++$i) { $test[] = array('id' => '105', 'name' => 'Psihius', 'age' => '29', 'upd_time' => '1245076167', 'pht_id' => '16'); } $memory = memory_get_usage(); $string = serialize($test); echo 'Memory: '.(memory_get_usage() - $memory).PHP_EOL; echo 'Strlen: '.strlen($string).PHP_EOL.PHP_EOL.PHP_EOL; unset($test, $string); $test = array(); for ($i = 0; $i < 1000; ++$i) { $test[] = array('id' => '105', 'name' => 'Psihius', 'age' => '29', 'upd_time' => '1245076167', 'pht_id' => '16'); } $memory = memory_get_usage(); foreach ($test as $k => $v) { foreach ($v as $key => $val) { if (is_numeric($val)) { $test[$k][$key] = (int)$val; } } } unset($k, $v, $key, $val); $memory2 = memory_get_usage(); $string = serialize($test); echo 'Memory: '.(memory_get_usage() - $memory).PHP_EOL; echo 'Memor2: '.(memory_get_usage() - $memory).PHP_EOL; echo 'Strlen: '.strlen($string).PHP_EOL.PHP_EOL.PHP_EOL; Результат: Код (Text): Memory: 176800 Strlen: 112899 Memory: 193296 Strlen: 129899 Memory: 103792 Memor2: 103792 Strlen: 112899 Вывод: однозначно стоит приводить данные к int/float если они таковыми являются. На данном примере позволяет съекономить 16КБ при серализации данных. Внутренности PHP судя по всему хранят данные в едином формате и к нужному типу приводится при обращении, так что забивать голову приведениями типов в нутри приложения для оптимизации использования памяти не нужно.
могу задачку подкинуть: выяснить что быстрее Записать\Чтение массива serialize\unserialize или var_export\include
Тест: влияние длины переменных на скорость выполнения скрипта. Существует миф, что переменные длинее 7 символов тормозят работу скрипта, а длинее 32 - еще сильнее. В цликле for выполняется инициализация перемнной, присвоение значения и удаление с помощью unset. Циклов - 100000. Символ доллара не учитывается. Длина 5 символов: Выполнено за 0.5471 сек. Выполнено за 0.5340 сек. Выполнено за 0.5444 сек. [/list:u] Длина 10 символов: Выполнено за 0.6092 сек. Выполнено за 0.5950 сек. Выполнено за 0.6126 сек. [/list:u] Длина 40 символов: Выполнено за 0.8944 сек. Выполнено за 0.8900 сек. Выполнено за 0.8976 сек. [/list:u] Длина имен переменных действительно влияет на быстродействие скрипта! ЗЫ. Код простой: Код (PHP): <?php for ($i=0; $i<1000000; $i++) { $myvarmyvarmyvarmyvarmyvarmyvarmyvarmyvar; $myvarmyvarmyvarmyvarmyvarmyvarmyvarmyvar = 1024; unset($myvarmyvarmyvarmyvarmyvarmyvarmyvarmyvar); }
Тест: влияние подавления ошибок на быстродействие скрипта. Код без ошибок: Код (PHP): <?php for ($i=0; $i<10000; $i++) { $var = array(); key_exists('key', $var); unset ($var); } Выполнено за 0.0146 сек. [/list:u] Теперь получим ошибку самого распространенного типа - Notice. Обычно эту ошибку подавляют символом @: Код (PHP): <?php for ($i=0; $i<10000; $i++) { $var = array(); @key_exists($var['key'], $var); unset($var); } Выполнено за 0.0456 сек.[/list:u] В 3 раза медленнее, чем без Notice! Еще хуже ситуация, если допускать ошибки типа Warning: Код (PHP): <?php for ($i=0; $i<10000; $i++) { @key_exists('key', $var); unset ($var); } Выполнено за 0.1339 сек.[/list:u] Падение производительности скрипта - 900%! P.S. На самом деле, тормозит не подавление ошибки а её генерация - символ @ лишь подавляет вывод ошибки на экран, но php её все равно обрабатывает и записывает в лог.
[vs], он не из-за нотиса тормозит, а из-за варнинга: у array_key_exists() вторым параметром должен быть массив.
Ну, я замерял ведь скорость всего приведеного скрипта ;-) В целом, конечно, да, одной операции, но чем больше скрипт, тем больше в нем может быть таких операций.