Подтверждение того, что preg_* работает быстрее ereg_* Мы специально не используем никаких сложных выражений, мы используем простейшие строки поиска, даже без захвата. Код (PHP): <?php $string = ''; for($i = 0; $i <= 10000; $i++) { $string .= 'abcdef[replacement]ghijklmn'; } $start[1] = microtime(true); $abc = ereg_replace('replacement', 'REPLACED', $string); echo microtime(true) - $start[1].'<br>'; $start[2] = microtime(true); $abc = preg_replace('/replacement/i', 'REPLACED', $string); echo microtime(true) - $start[2].'<br>'; ?> Результат: Код (Text): 10.284742832184 0.013195037841797 Комментарии излишни
Задумайтесь, кстати, что влияет. Подавление сообщения об ошибке или сама ошибка. Особо впечатлительные интерпретируют эти выводы как - использования собаки замедляет ваши сценарии в 9 раз.
ребята, у PHP есть одна неприятная для подсчетов особенность: Код (PHP): <?php $string = ''; $start = array(); for($i = 0; $i <= 100; $i++) { $string .= 'abcdef[replacement]ghijklmn'; } $start[1] = microtime(true); for($i = 0; $i <= 10000; $i++) { $abc = preg_replace('/replacement/i', 'REPLACED', $string); } echo microtime(true) - $start[1].'<br>'; $start[2] = microtime(true); for($i = 0; $i <= 10000; $i++) { $abc = preg_replace('/replacement/i', 'REPLACED', $string); } echo microtime(true) - $start[2].'<br>'; exit; ?> Стабильный результат: Код (Text): 0.453883886337 0.365996837616 Тот код, который проверяется первым - всегда кажется более медленным, потому стоит учитывать это и проверять в два разных скрипта. Пример с preg_ ereg_: Код (Text): Ereg - первый e 0.856323003769 p 0.037899017334 Ereg - второй p 0.0398910045624 e 0.797086000443 На небольших разницах(до 50%) это способно сыграть критическую роль (проверил на сообственном опыте). Естественно, тормознутости ерега это не отменяет.
Надеюсь, тест проводился в консоли? При тестировании необходимо отключать все программы, которые могут 20-100% на совсем незначительный срок (логгеры, нотайсеры, чаты, аськи, почтовики), а так же фаерволлы, антивирусы...
Kreker, код выше: Код (Text): shock@shock:~$ php -f /home/shock/Web/test.php 0.46493601799 0.371444940567 shock@shock:~$ php -f /home/shock/Web/test.php 0.451848983765 0.376871109009 shock@shock:~$ php -f /home/shock/Web/test.php 0.421268939972 0.370434045792 Сомневаюсь, что так стабильно могут влиять программы
TheShock Чтобы этого избежать, достаточно для каждого варианта запускать сркипт отдельно. ЗЫ. Psih а де ссылки?
Тема теста сегодня вполне прикладная и напрямую повлияла на метод вызова методов класса. Тема теста: $this->$call($arg) vs call_user_func(array($this, $call), $arg) vs switch ($call) { case 'method1': $this->method1($arg); break; }. Сделал 2 теста - первый когда имя метода совпадает с тем, что в $call. Второй, это когда имя метода имеет префикс, который мы добавляем перед $call при вызове. Тест первый: Код (PHP): <?php define('MAX', 100000); class Test { final public function __construct() { } final public function __destruct() { } final public function run_test1($current) { $this->$current('test1'); } final public function run_test2($current) { call_user_func(array($this, $current), 'test2'); } final public function run_test3($current) { switch ($current) { case 'test1': $this->test1('test3'); break; case 'test2': $this->test2('test3'); break; case 'test3': $this->test3('test3'); break; } } final private function test1($param) { } final private function test2($param) { } final private function test3($param) { } } $test = new Test(); $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test1('test1'); $test->run_test1('test2'); $test->run_test1('test3'); } $time2 = microtime(true); echo 'Test with $this->$k: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test2('test1'); $test->run_test2('test2'); $test->run_test2('test3'); } $time2 = microtime(true); echo 'Test with call_user_func: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test3('test1'); $test->run_test3('test2'); $test->run_test3('test3'); } $time2 = microtime(true); echo 'Test with switch: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; Результаты: Код (Text): Test with $this->$k: 8.2953500748 Test with call_user_func: 8.9828510284 Test with switch: 13.3120439053 Тест 2 (этот меня интересовал больше, т.к. это конкретно мой случай). Дополнительно добавил тест с __call: Код (PHP): <?php define('MAX', 100000); class Test { final public function __construct() { } final public function __destruct() { } final public function run_test1($current) { $this->{'event_'.$current}('test1'); } final public function run_test2($current) { call_user_func(array($this, 'event_'.$current), 'test2'); } final public function run_test3($current) { switch ($current) { case 'test1': $this->event_test1('test3'); break; case 'test2': $this->event_test2('test3'); break; case 'test3': $this->event_test3('test3'); break; } } final public function __call($method, $params) { $this->{'event_'.$method}($params[0]); } final public function run_test4($current) { $this->$current('test4'); } final private function event_test1($param) { } final private function event_test2($param) { } final private function event_test3($param) { } } $test = new Test(); $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test1('test1'); $test->run_test1('test2'); $test->run_test1('test3'); } $time2 = microtime(true); echo 'Test with $this->$k: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test2('test1'); $test->run_test2('test2'); $test->run_test2('test3'); } $time2 = microtime(true); echo 'Test with call_user_func: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test3('test1'); $test->run_test3('test2'); $test->run_test3('test3'); } $time2 = microtime(true); echo 'Test with switch: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test4('test1'); $test->run_test4('test2'); $test->run_test4('test3'); } $time2 = microtime(true); echo 'Test with __call: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; Результаты: Код (Text): Test with $this->$k: 8.5323679447 Test with call_user_func: 9.2136681080 Test with switch: 13.2927098274 Test with __call: 12.6840810776 Итог: $this->{'prefix_'.$call}() - герой дня. call_user_func тоже подходит. switch case вобщем-то как и ожидалось - аутсайдер. __call как ни странно оказался сильно медленее, я ожидал меньшее отставание. Вобщем-то __call используется для method overload и его разумное использование вряд-ли скажется на вашем проекте. Со switch case есть ещё один момент - чем больше case'ов, тем медленее будет оно работать. В моём случае ожидается до 30-40 case'ов, что я думаю скажется зверски, особенно если учитывать что конкретно эта часть будет дёргаться AJAX'ом раз в 5 секунд каждый юзером, а онлайн планируется порядка 3-4 тысяч для начала, в последствии до 20-25 тысяч.
Вывод о switch case подтверждается следующим тестом: Код (PHP): <?php define('MAX', 100000); class Test { final public function __construct() { } final public function __destruct() { } final public function run_test1($current) { $this->{'event_'.$current}('test1'); } final public function run_test2($current) { call_user_func(array($this, 'event_'.$current), 'test2'); } final public function run_test3($current) { switch ($current) { case 'test1': $this->event_test1('test3'); break; case 'test2': $this->event_test2('test3'); break; case 'test3': $this->event_test3('test3'); break; case 'test4': $this->event_test4('test3'); break; case 'test5': $this->event_test5('test3'); break; case 'test6': $this->event_test6('test3'); break; case 'test7': $this->event_test7('test3'); break; case 'test8': $this->event_test8('test3'); break; case 'test9': $this->event_test9('test3'); break; case 'test10': $this->event_test10('test3'); break; } } final public function __call($method, $params) { $this->{'event_'.$method}($params[0]); } final public function run_test4($current) { $this->$current('test4'); } final private function event_test1($param) { } final private function event_test2($param) { } final private function event_test3($param) { } final private function event_test4($param) { } final private function event_test5($param) { } final private function event_test6($param) { } final private function event_test7($param) { } final private function event_test8($param) { } final private function event_test9($param) { } final private function event_test10($param) { } } $test = new Test(); $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test1('test1'); $test->run_test1('test2'); $test->run_test1('test3'); $test->run_test1('test4'); $test->run_test1('test5'); $test->run_test1('test6'); $test->run_test1('test7'); $test->run_test1('test8'); $test->run_test1('test9'); $test->run_test1('test10'); } $time2 = microtime(true); echo 'Test with $this->$k: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test2('test1'); $test->run_test2('test2'); $test->run_test2('test3'); $test->run_test2('test4'); $test->run_test2('test5'); $test->run_test2('test6'); $test->run_test2('test7'); $test->run_test2('test8'); $test->run_test2('test9'); $test->run_test2('test10'); } $time2 = microtime(true); echo 'Test with call_user_func: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; $time = microtime(true); for ($i = 0; $i < MAX; ++$i) { $test->run_test3('test1'); $test->run_test3('test2'); $test->run_test3('test3'); $test->run_test3('test4'); $test->run_test3('test5'); $test->run_test3('test6'); $test->run_test3('test7'); $test->run_test3('test8'); $test->run_test3('test9'); $test->run_test3('test10'); } $time2 = microtime(true); echo 'Test with switch: '.number_format($time2 - $time, 10, '.', '').PHP_EOL.PHP_EOL; Результаты: Код (Text): Test with $this->$k: 26.2422990799 Test with call_user_func: 28.9457180500 Test with switch: 62.2703588009 Тот же тест, только при кол-ве итераций 1 Код (Text): Test with $this->$k: 0.0003399849 Test with call_user_func: 0.0009131432 Test with switch: 0.0010728836
А заявку можно? Меня интересует что работает шустрее: mysqli или PDO? Так же интересно как изменится ситуация на php 5.3.0
скорее всего, одинаково, т.к. юзают один и тот же драйвер. Разница возможно будет лишь в мелочах. В ПХП 5.3 появился mysqlnd -http://dev.mysql.com/downloads/connector/php-mysqlnd/
кстати, это и выглядит короче и работает быстрее, а следовательно - меньше влияет на результаты теста Код (Text): for ($i = MAX; $i--;) {
И сразу результаты тестов в качестве доказательства, что обратный цикл втрое быстрее, чем прямой Код (Text): shock@shock:~$ cat direct.php Код (PHP): <?php define('MAX', 100000); $s = microtime(1); for ($i = 0; $i < MAX; $i++) { } $e = microtime(1); echo $e - $s; ?> Код (Text): shock@shock:~$ cat reverse.php Код (PHP): <?php define('MAX', 100000); $s = microtime(1); for ($i = MAX; $i--;) { } $e = microtime(1); echo $e - $s; ?> Код (Text): shock@shock:~$ php -f direct.php 0.0375878810883 shock@shock:~$ php -f direct.php 0.0357940196991 shock@shock:~$ php -f direct.php 0.026978969574 shock@shock:~$ php -f reverse.php 0.00968289375305 shock@shock:~$ php -f reverse.php 0.0103600025177 shock@shock:~$ php -f reverse.php 0.0092179775238 Итоговый результат - 0,1 против 0,03
флоппик Koc Насчёт скорости - скорее всего да, разницы сильно не будет. Зато я думаю будет достаточно большая разница в потреблении памяти, т.к. PDO это PHP Data Objects, а объекты очень любят память mysqlnd будет работать с любой либой, которая основана на libmysql, т.е. mysql, mysqli, PDO. Будет жрать в 2 раза меньше памяти и более быстро работать из-за отсуствия необходимости 2 раза копировать данные - один раз в libmysql C, другой раз в PHP. Koc А что мешает тебе сделать тест самому? На винде это делается как 2 пальца об асфальт.
Psih ты подтвердил мои предположения. То есть я ставлю бинарник 5.3.0 и у меня автоматом mysqli работает через nd? А мешает.. Я думаю, что кто-то другой сделает этот тест)
Очередная злая цель: Выяснить что быстрее сохранение/чтение массива в файл serialize или var_export А ещё зависит ли скорость от типа массива (числовой или смешанный) Код (PHP): <? include_once "timer.class.php"; print "<pre>"; $_GET['process']=!$_GET['process']?"Save":$_GET['process']; $_GET['type']=!$_GET['type']?"Serial":$_GET['type']; $_GET['array_type']=!$_GET['array_type']?"Numbers":$_GET['array_type']; function GenArray(){ $res=false; switch($_GET['array_type']){ case "Words": $res=array(); $s=array("Q"=>0,"W"=>0,"E"=>0,"R"=>0,"T"=>0,"Y"=>0, "U"=>0,"I"=>0,"O"=>0,"P"=>0,"A"=>0,"S"=>0, "D"=>0,"F"=>0,"G"=>0,"H"=>0,"J"=>0,"K"=>0, "L"=>0,"Z"=>0,"X"=>0,"C"=>0,"V"=>0,"B"=>0, "N"=>0,"M"=>0,"1"=>0,"2"=>0,"3"=>0,"4"=>0, "5"=>0,"6"=>0,"7"=>0,"8"=>0,"9"=>0,"0"=>0); for($i=0;$i<1000;$i++){ $res[(implode("",array_rand($s,6)).$i)]=implode("",array_rand($s,20)); } break; default; $res=range(1,1000); } return $res; } function SaveToSerial($i){ Timer::Run("off"); $arr=GenArray(); Timer::Modifer("main","off"); file_put_contents("data/file_".$i.".data.php",serialize($arr)); } function ReadToSerial($i){ $fp=file_get_contents("data/file_{$i}.data.php"); return unserialize($fp); } function SaveToArray($i){ Timer::Run("off"); $arr=GenArray(); Timer::Modifer("main","off"); file_put_contents("data/file_".$i.".data.php",'<?$data='.var_export($arr,1).'?>'); } function ReadToArray($i){ include "data/file_{$i}.data.php"; return $data; } $func=$_GET['process']."To".$_GET['type']; if(!function_exists($func)) die("Error, Func does not exists"); Timer::Run("main"); for($i=0;$i<1000;$i++){ $func($i); } print Timer::End("main",'',"{$_GET['type']} {$_GET['process']} Time (array type - {$_GET['array_type']}): {time}\r\n"); print "</pre>"; ?> Результат: Serialize быстрее по всем показателям, скорость зависит от типа массива, числовой быстрее Однако, я всё равно буду использовать var_export, удобнее потому что редактировать
Может кому пригодится Класс - таймер Код (PHP): <? class Timer { protected static $time=array(); /** $cnf = array( log_autowrite => true/false - автоматически писать в лог log_name => Файл в логом log_tpl => Дефолтный шаблон записи в лог ({comments} - комментарии {time} - итоговое время) ) */ public static $cnf=array("log_autowrite"=>1,"log_name"=>"log.txt", "log_tpl"=>"{comments} Time => {time} \r\n"); /** Начинает отсчёт времени @param string $name - Идентификатор часиков @return float; */ static function Run($name){ self::Set($name,self::GetTimeNow()); return self::Get($name); } /** Возвращает значение часиков @param string $name - Идентификатор часиков @return float; */ static function Get($name){ $name=strtolower($name); return (float)self::$time[$name]; } /** Устанавливает значение часикам @param string $name - Идентификатор часиков @param float $value - Значение */ static function Set($name,$value){ $name=strtolower($name); self::$time[$name]=(float)$value; } /** Возвращает текущее время в миллисекундах @return float; */ static function GetTimeNow(){ return microtime(1); } /** Заканчиват отсчёт времени, пишет в лог если log_autowrite => true @param string $name - идентификатор записи @param string $comments - Комментарии @param string $log_tpl - Шаблон, если false юзаем дефолтный @return string; */ static function End($name,$comments='',$log_tpl=false){ $time=self::GetTimeNow()-self::Get($name); if(!$log_tpl)$log_tpl=self::$cnf['log_tpl']; $res=str_replace(array("{comments}","{time}"),array($comments,$time),$log_tpl); if(self::$cnf['log_autowrite']) self::LogWrite($res); return $res; } /** Вносит поправку во время @param string $name_modifer - Часики в которые нужно внести поправку @param string $name_modificator - Часики с которых поправка будет вноситься */ static function Modifer($name_modifer,$name_modificator){ self::Set($name_modifer,(self::Get($name_modifer)+(self::GetTimeNow()-self::Get($name_modificator)))); } /** Очищает часики @param mixed $name - Идентификаторы часиков (string or array) */ static function Clear($name){ if(!is_array($name)){ self::Set($name,0); }else{ for($i=0,$c=count($name);$i<$c;$i++) self::Clear($name[$i]); } } /** Пишет в лог @param string $res - текст для записи @return string; */ static function LogWrite($res){ $fp=fopen(self::$cnf['log_name'],'a+'); fputs($fp,$res); fclose($fp); return $res; } } ?> Example Код (PHP): <? include "timer.class.php"; Timer::Run("main"); $str="fksl;dkfj siojt 4u5903u90856 9sdjgljspdgjdp gp9eu9068opdufglh; kfjfopgh ophkfghif0586"; for($i=0;$i<1000;$i++){ Timer::Run("time_off"); for($l=0;$l<1000;$l++){ preg_match("#[^a-zA-Z]+#isU",$str); } Timer::Modifer("main","time_off"); } print Timer::End("main","Main Off"); ?>
microtime(1); $cnf - это $cfg ? И тут намного лучше был бы нестатический класс. Код (PHP): <? $timer1 = new Timer; $timer2 = new Timer; $timer1->start(); action1(); $timer2->start(); action3(); $timer1->stop(); action5(); $timer2->stop(); Хотя у самого есть такой класс, придерживаюсь политики, что он не нужен, ибо значительно влияет на время эксперимента
пусть гора идёт к магамеду это переменная cnf Чем? он хуже всем, хотя бы потому что не глобальный затестил, на 0.0044 дольше только на выводы при сравнении это не влияет
что быстрее in_array или array_search, зависит ли скорость от типа ключей (текстовый или числовой) Код (PHP): <? include_once "timer.class.php"; $_GET['func']=!$_GET['func']?"in_array":$_GET['func']; $_GET['type']=!$_GET['type']?"Numbers":$_GET['type']; if(!in_array(strtolower($_GET['func']),array("in_array","array_search"))) die("Func not found"); function GenArray(){ $res=array(); $s=array("Q"=>0,"W"=>0,"E"=>0,"R"=>0,"T"=>0,"Y"=>0, "U"=>0,"I"=>0,"O"=>0,"P"=>0,"A"=>0,"S"=>0,"D"=>0, "F"=>0,"G"=>0,"H"=>0,"J"=>0,"K"=>0,"L"=>0,"Z"=>0,"X"=>0, "C"=>0,"V"=>0,"B"=>0,"N"=>0,"M"=>0,"1"=>0,"2"=>0,"3"=>0, "4"=>0,"5"=>0,"6"=>0,"7"=>0,"8"=>0,"9"=>0,"0"=>0); switch($_GET['type']){ case "Words": for($i=0;$i<5000;$i++) $res[(implode('',array_rand($s,5)).$i)]="ABC_$i"; break; default; $_GET['type']="Numbers"; for($i=0;$i<5000;$i++) $res[$i]="ABC_$i"; } return $res; } print "<pre>"; $arr=GenArray(); Timer::Run("main"); for($i=0;$i<5000;$i++){ call_user_func($_GET['func'],"ABC_$i",$arr); } print Timer::End("main",'',"Array type:{$_GET['type']}; Function: {$_GET['func']}, Итоговое Время => {time}\r\n"); print "</pre>"; ?> array_search быстрее, но при повторном обновлении страницы тормозится...почему-то С чисвловыми ключами обе работают немного быстрее
Mr.M.I.T. извини, но код ужастен и малопонятен. Это разве хороший стиль? Код (PHP): <? $s = array_fill_keys(array_merge(range('A', 'Z'), range('0', '9')), 0); Зачем эти все проверки, зачем влияющая на статистику call_user_func($_GET['func'], вместо нормального вызова функции. Каша какая то. Непонятно, что какая строка делает.