[PHP] Быстродействие
ну дык загрузить данные из файла один раз а не 1000
<?выдаёт
function test($n) {
return preg_replace("/\W/s","",file_get_contents("***.php").$n);
}
$times=Array;
for($i=0;$i<500;$i++) {
$stime=microtime(true);
$tmp=test($i);
$times[]=microtime(true)-$stime;
}
$average=0;
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
echo $average."<br/>".$delta;
?>
0.040363070011139
0.01550553009738
Я про то, что время постоянно меняется... ещё ясно, если бы $times[0] было большим, а всё остальное маленьким - но оно и посередине может быть то 0.09, то 0.035...
В твоем случае - надо брать среднее время и не морочить голову.
Еще умные люди сказали: В одну воду дважды не ступишь.
статистику ботай хуле...
А ещё попробуй ereg_replace. Иногда в экзотических случаях регекспов оно бывает сильно быстрее. Но редко, правда.
Повторяю ещё раз - в данном случае мне не нравится не производительность вообще ("почему всё работает так медленно?" а проблемы замера производительности ("почему время работы так непостоянно?").
<?
$content = file_get_contents("***.php");
function test($n) {
global $content;
return preg_replace( "/\W/s","", $content.$n );
}
$times=Array;
for($i=0;$i<500;$i++) {
$stime=microtime(true);
$tmp=test($i);
$times[]=microtime(true)-$stime;
}
$average=0;
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
echo $average."<br/>".$delta;
?>
Ещё попробуй увеличить размер файла - это повысит точность измерений.
наверняка меняются внешние условия... например - расположение головок на винте
выдаёт
<?
function test($n) {
return preg_replace("/\W/s","",$GLOBALS['str'].$n);
}
$str=file_get_contents("***.php");
$times=Array;
for($i=0;$i<500;$i++) {
$stime=microtime(true);
$tmp=test($i);
$times[]=microtime(true)-$stime;
}
$average=0;
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
echo $average."<br/>".$delta;
?>
0.038284560203552
0.014701287154406
В твоем случае - надо брать среднее время и не морочить голову.Этот test.php я привёл просто для примера (ну и написал его - чтобы самому убедиться, что такое действительно может быть).
Есть реальное приложение, которое сейчас надо жёстко оптимизировать - если примерно описать, то там есть одна сложная функция, которая работает в среднем 0.1-0.15с. И, если в ней выделить нечто типа цикла, и на каждой итерации (а их около 1000) выводить время - получится, что вообще-то одна итерация (там практически никаких сложных действий не производится) работает около 0.00001с (10^-5с но иногда время работы одной итерации - 0.01с (10^-2с) (несмотря на то, что в ней совершаются такие же действия, как и в предыдущей). И, получается, за счёт этих "медленных" итераций и складывается всё время работы функции - которое иначе было бы на порядок меньше...
ЗЫ:
выдаёт на экран
<?
function test($n) {
return preg_replace("/\W/s","",$GLOBALS['str'].$n);
}
$str="";
for($i=0;$i<150;$i++) {
$str.=chr(mt_rand(0,255;
}
$times=Array;
for($i=0;$i<500;$i++) {
$stime=microtime(true);
$tmp=test($i);
$times[]=microtime(true)-$stime;
}
$fp=fopen("times.txt","w");
fwrite($fp,implode("\r\n",$times;
fclose($fp);
$average=0;
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
$min=1;
foreach($times as $time) $min=($min>$time)?$time:$min;
echo $average."<br/>".$delta."<br/>".$min;
?>
0.00017553043365479При этом в times.txt есть строки типа
0.00013895696275723
0.00016093254089355
Таких отклонений я сейчас в файле из 500 строк насчитал 17.
0.00016379356384277
0.00016403198242188
0.0020339488983154
0.00017499923706055
0.00016498565673828
В реальном же приложении, похоже, единственные отличие - эти редкие отклонения ещё сильнее отличаются от нормы, и, в результате, и создают всю погоду...
Потому что дисковые операции.Не потому что, как видно...
Ещё попробуй увеличить размер файла - это повысит точность измерений.Ага, а ещё можно рассмотреть сферического коня в вакууме - только мне это не поможет. Потому что в реальном приложении тысяча мелких операций, и тормоза в три порядка на десяти из них на порядок увеличивает общее время работы...
$average=0;Numerical Recipes in PHP
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
$min=1;
foreach($times as $time) $min=($min>$time)?$time:$min;
![](/images/graemlins/grin.gif)
wtf?
Мысли вслух
Если поставить длину строки 50, и умножить время на 1000 (чтобы в нормальном формате выдавалось) - получится
2.817521
26.10405610361
0.12493133544922
Чем, по-твоему, "операционные системы реального" отличаются от обычных? В данной ситуации похоже на то, что ОС в момент выполнения переключила процессор на какую-нибудь постороннюю задачу, отсюда и кажущиеся тормоза. Считай время работы в среднем. В добавок время работы таймера может быть неточным. Короче, копай в этом направлении.
Чем, по-твоему, "операционные системы реального" отличаются от обычных?В смысле?
В данной ситуации похоже на то, что ОС в момент выполнения переключила процессор на какую-нибудь постороннюю задачу, отсюда и кажущиеся тормоза.Это ясно...
Проблема в том, что средняя загрузка процессора у меня - 2-3%, а моё приложение из-за этих переключений работает в 10 раз (а не на эти 2-3%) медленнее, чем могло бы.
Ну и хочется узнать, неужели нет никакого механизма "запирания" процессора, пусть даже на небольшое время, чтобы моё приложение работало всего 0.01с - но все эти 0.01с ОС не переключала процессор на другие процессы?
Считай время работы в среднем. В добавок время работы таймера может быть неточнымЕсть 1000 итераций, 990 из них тратят 0.9x-1.1х времени, 10 из них тратят 1000х времени - в результате время работы одной итерации "в среднем" получается 10х - в десять раз больше, чем ожидаемые 0.9х-1.1х, которые и уходят, по-видимому, на "полезные" действия внутри итерации - что-то не нравятся мне такие погрешности - в десять раз на не таких уж и малых значениях.
По моему ты хернёй страдаешь. Измерять время меньше 0.01 бессмыслено, тем более в ПХП. Интерпретатор может запускать какие-то свои процессы, вроде сборки мусора, операционка может переключаться на другие процессы, процессор может ждать подгрузки данных из памяти в кэш или из свопа в память и т.д. Если надо так жёстко оптимизировать - либо пиши на С/С++ или чём-то подобном, либо кэшируй результаты работы скриптов.
Есть 1000 итераций, 990 из них тратят 0.9x-1.1х времени, 10 из них тратят 1000х времени - в результате время работы одной итерации "в среднем" получается 10х - в десять раз больше, чем ожидаемые 0.9х-1.1х, которые и уходят, по-видимому, на "полезные" действия внутри итерации - что-то не нравятся мне такие погрешности - в десять раз на не таких уж и малых значениях.Минимальный код в студию, чтоле. А то выходит что-то вроде такого:
"У меня есть программа, в ней 10000 итераций, 9999 отрабатывают за 0.00001, а одна - за 10 секунд. Что делать?" при том что в коде может быть что-то типа
for( int i = 0; i < 10000; i++ ) {
if( i == 239 ) {
sleep( 10000 );
}
}
Тот пример, что ты привёл либо скачет в пределах от x до 2x, либо за гранью погрешности вычислений. И проблема там, как мне думается, в неоднородности среды и желаниях интерпретатора иногда справлять какие-то небольшие свои нужды, вроде переалокаций памяти и т.д.
Измерять время меньше 0.01 бессмыслено, тем более в ПХП.А зачем тогда нужна функция microtime(true возвращающая время с точностью до хрен-знает-какого знака после запятой?
Интерпретатор может запускать какие-то свои процессы, вроде сборки мусора,А если я хочу отключить эти "свои процессы" во время исполнения скрипта?
операционка может переключаться на другие процессы,Я понимаю, когда загруженность процессора на 90% влечёт замедление работы скрипта в 10 раз. Но когда такой эффект появляется из-за загруженности процессора на 2-3% - не понимаю.
процессор может ждать подгрузки данных из памяти в кэш или из свопа в памятьВ данной ситуации, вроде как, оперативной памяти более чем достаточно; более того, используемая скриптом память на несколько порядков меньше объёма кэша.
Если происходит какой-то такой тупняк - хотелось бы знать, как можно сказать "я - очень лёгкий скрипт, памяти мне надо всего ничего, поэтому возиться с свопом не надо, можно сразу всё целиком положить в кэш".
Если надо так жёстко оптимизировать - либо пиши на С/С++ или чём-то подобномТипа php - язык для детей в песочнице, а серъёзные приложения с нагрузкой больше 10 хитов в секунду на нём писать нельзя, потому что интерпретатор иногда начинает тупить и для скрипта, исполняющегося 0.01с тратит лишние 0.1с на обдумывание каких-то своих сугубо личных вещей, к делу никак не относящихся?
либо кэшируй результаты работы скриптов.А в каком формате кэшировать?
А если результатов много - как кэш парсить?
А что делать, если функция доставания данных из строки-кэша так же тормозит?
Тот пример, что ты привёл либо скачет в пределах от x до 2x, либо за гранью погрешности вычислений.Тот пример, который привёл я, в последнем случае скачет в пределах от х до 100х.
Или для тебя разница двух значений microtime(true) в виде
0.0001***уже за гранью погрешности? У меня почему-то такое ощущение, что, если бы эти результаты были за гранью погрешности вычислений, значения бы были случайными от 0 до 0.01, а не держались бы за единичными очень сильно отличающимися (на порядки) исключениями так чётко в 0.0001.
0.0001***
(куча строк 0.0001***)
0.01***
(опять куча строк 0.0001***)
в неоднородности средыwtf?
и желаниях интерпретатора иногда справлять какие-то небольшие свои нужды, вроде переалокаций памятиА где в моём примере это может понадобиться?
Ну ещё понятно, если бы тормоза происходили на первой/второй итерации, но когда происходят сотни абсолютно одинаковых итераций, не тратящих лишней памяти, а где-то посередине вдруг происходят какие-то тормоза - уже непонятно.
А в каком формате кэшировать?А если результатов много - как кэш парсить?А что делать, если функция доставания данных из строки-кэша так же тормозит?Идеально - сгенерировать все страницы и отдавать их статически. Либо всё сразу генерируешь, либо по запросу и сохраняешь результаты на разумное время. Если система должна выдавать данные для каждого пользователя свои, то тоже генерировать их 1 раз, сохранять в БД или в файли и выдавать уже готовые.
Если система должна выдавать данные для каждого пользователя свои, то тоже генерировать их 1 раз, сохранять в БД или в файли и выдавать уже готовые.Рассмотрим такую ситуацию: есть Очень Большой шаблон (для каждого пользователя для каждого запроса сохранять такой в БД не получится - уж слишком большой есть данные, отдельно получающиеся для каждого пользователя и каждого запроса, которые в этот шаблон надо подставить (они уже кэшируются есть почти предельно оптимизированная (можно выиграть ещё один процент времени за счёт очень сильного переписывания - и не факт, что этот один процент потом не потратится за счёт более сложного разбора скрипта) функция подстановки данных в шаблон - и тормоза возникают как раз в этой функции. Что посоветуешь?
А где в моём примере это может понадобиться?Ну ещё понятно, если бы тормоза происходили на первой/второй итерации, но когда происходят сотни абсолютно одинаковых итераций, не тратящих лишней памяти, а где-то посередине вдруг происходят какие-то тормоза - уже непонятно.Ну например так. Интерпретатор заалокировал кучу памяти, куда пихает свои переменные. Когда память забивается, он запускает сборку мусора, удаляя переменные, на которые нет ссылок. Или запускает раз в х-нцать тысячных секунд. Хотя вроде бы в PHP переменные как раз сразу удаляются и сборки мусора нет. Может быть у него куча сильно форматированной стаёт, и он её перестраивает, собирая все занятые куски памяти в одном месте.
Та оптимизация, которой ты занимаешься возможна только в языках низкого уровня, где профайлер может показать, какой код сколько скушал вплоть до ассемлерных команд, как алокировалась память и т.д. А ты это делаешь в интерпретируемом языке, а нам не показываешь реальный код, не говоришь даже ничего про операционку и параметры системы и т.д. Да мало ли что там может быть.
Может ты массив передаёшь в функцию, и в 10 случаях из 1000 меняешь его элемент, а в остальных - только читаешь. Вот у тебя и вызывается в 10 случаях копирование всего массива, чтобы его изменить, а в остальных интерпретатор обходится без этого. А может просто запущен IM-клиент какой-нибудь, который раз в секунду куда-то лезет по сети, и операционка переключается на его процесс, что может быть связанно с некоторыми накладными расходами. А может интерпретатору просто нравится неравномерно памятью ворочать в процессе работы.
Телепаты в отпуске, в общем.
Так ты ничего не сказал ни о природе данных (как часто обновляются, например ни о природе пользователей (10 пользователей непрерывно что-то грузят или 1000 раз в час страничку обновляют). Да и в любом случае надо вникать в задачу - так что-то конкретное советовать бестолку.
А если динамический, то почему данные в него не вставляются сразу, а только после генерации шаблона?
Ну например так. Интерпретатор заалокировал кучу памяти, куда пихает свои переменные. Когда память забивается, он запускает сборку мусора, удаляя переменные, на которые нет ссылок. Или запускает раз в х-нцать тысячных секунд.В моих примерах память забиваться не должна.
Точнее, не забивается, если в начале сделать $times=array_fill(0,1000,0) - это на ситуацию не повлияет (сам проверял)
Если он запускает её по расписанию - хотелось бы знать, как можно это отключить.
Та оптимизация, которой ты занимаешься возможна только в языках низкого уровняА в языках высокого уровня цикл из 1000 итераций всегда может работать в 10000 раз дольше, чем исполняется одна итерация?
А ты это делаешь в интерпретируемом языке, а нам не показываешь реальный код,А чем плох тот код, который я тут постил? В нём тоже среднее время выполнения - на порядок больше, чем количество итераций*ожидаемое время выполнения одной итерации.
Для тех, кто в танке: код
<?
function test($n) {
return preg_replace("/\W/s","",$GLOBALS['str'].$n);
}
$str="";
for($i=0;$i<50;$i++) {
$str.=chr(mt_rand(0,255;
}
$times=array_fill(0,1000,0);
for($i=0;$i<1000;$i++) {
$stime=microtime(true);
$tmp=test($i);
$times[$i]=(microtime(true)-$stime)*1000;
}
$fp=fopen("times.txt","w");
fwrite($fp,implode("\r\n",$times;
fclose($fp);
$average=0;
foreach($times as $time) $average+=$time;
$average/=count($times);
$delta=0;
foreach($times as $time) $delta+$time-$average)*($time-$average;
$delta/=count($times);
$delta=sqrt($delta);
$min=1;
foreach($times as $time) $min=($min>$time)?$time:$min;
$count=0;
foreach($times as $time) if($time<(1.2*$min $count+=1;
$count/=count($times);
echo $average."<br/>".$delta."<br/>".$min."<br/>".$count;
?>
выдаёт
1.270655632019
13.431875691522
0.11491775512695
0.948
А может просто запущен IM-клиент какой-нибудь, который раз в секунду куда-то лезет по сети, и операционка переключается на его процесс, что может быть связанно с некоторыми накладными расходами.Может.
Только тогда "некоторые расходы" получаются уж больно большими - каждый раз этот im-клиент попадает на время исполнения цикла, который так бы отработал всего за 0.11с - и растягивает время выполнения скрипта на 1с - тогда у меня диспетчер задач должен загрузку процессора 90% показывать...
не говоришь даже ничего про операционку и параметры системы и т.д.Какие параметры тебя интересуют?
Шаблон более-менее постоянный (по крайней мере, каждую секунду не обновляется).
Ну?
> работает так медленно?" а проблемы замера производительности ("почему время работы так непостоянно?").
Это общее свойство многих современных систем. Это вызвано многозадачной ОС, всякими потоками/блокироваками, сборкой мусора, кэшами процессора, сетью итп.
Кстати, по поводу сборки мусора. В обычных языках типа C/C++ автоматической сборки мусора нет и многие думают, что этой проблемы нет. На самом деле, с malloc/free — такая же ситуация. Некоторые вызовы malloc работают быстро, некоторые — долго.
Я наблюдаю такие явления почти каждый день. Встречались интересные случаи, например, когда добавление в программу отладочных printf ускоряло ее в 8 (восемь) раз. Это было связано с тем, что printf делал syscall, который вызывал переключение на другой процесс и семафоры брались в другом порядке.
Профилировать в таких услвояих достаточно тяжело, однако, возможно.
Что бы я посоветовал:
1) Мерять время с большой точностью --- использовать по возможности rdtsc. Ни в коем случае не использовать функции делающие syscall-ы.
2) Аналогично с печатью. Весь отладочны вывод накапливать в одну большую текстовую строку, выделенную заранее, потом пачкой скидывать в файл. Любые замеры времени и печать, использующие syscalls очень сильно искажает замеры.
3) Использовать Профайлер. oprofile (для Linux) или VTune (для Windows). Позволяет узнать вещи, которые по другому никак не узнал бы. Очень полезная вещь. Полезно смотреть не только выполняемые инструкции, но и кэш-промахи и неправильно предсказанные переходы
4) Приложение может бы ограничено не сколько процессором, сколько памятью. Например, объем данных может быть близок к объему кэша. В этом случае программа работает хорошо, но стоит произвести какое-нибудь прерывание, например, переключиться на другой фоновой процесс, как кэш тут же спортится и будет сильное торможение. Это, кстати, может объяснять как фоновой процесс жрущий 2-3% процессора может вызывать замедление в несколько раз.
5) Используя средства ОС можно смотреть сколько раз процесс делал page fault, context switch и т.п. Во время работы периодически их проверять. Возможно обнаружится корреляция между временем очередного цикла и количеством context switch.
2) Аналогично с печатью. Весь отладочны вывод накапливать в одну большую текстовую строку, выделенную заранее, потом пачкой скидывать в файл.В моём примере так и происходит
![](/images/graemlins/smile.gif)
Приложение может бы ограничено не сколько процессором, сколько памятью. Например, объем данных может быть близок к объему кэша. В этом случае программа работает хорошо, но стоит произвести какое-нибудь прерывание, например, переключиться на другой фоновой процесс, как кэш тут же спортится и будет сильное торможение.А можно ли как-нибудь запретить это - типа "тут я начинаю цикл, ничего никуда не переключайте... всё, закончил"?
1, 3, 5 - боюсь, я не очень хорошо в этом разбираюсь... можно как-нибудь на пальцах объяснить?
![](/images/graemlins/smile.gif)
foreach($times as $time) if($time<(1.2*$min $count+=1;В разбросе в 1.2 раза нет ничего криминального. То, что ты насчитал не показательно. Надо посчитать, сколько времени занимают 10% самых долгих итераций (или сколько там надо?) по отношению ко всему времени. Ну, пусть не 10%, а x%. Если их работы порядка, скажем, 2x%, то это нормально. Если разброс между максимумом и минимумом меньше, чем в 2-3 раза, то тоже нормально. Ты же говоришь, что 1% итераций съедает 90% времени, но на твоих примерах этого нет. И если в действительности такое и происходит, то тут виноват не PHP, а то, что ты не так написал код, не зная всех тонкостей. Если же тебе не нравится, что 1% итераций, съедают 3% времени, то это твоя личная половая драмма. И на PHP ты это никак не изменишь, скорее всего.
Ну так распаарси шаблон один раз, но вместо подстановки реальных данных подставляй строки вида "<?=\$data[$n]?>", предварительно заменив в нём все < и > на < и > соответсвенно. А потом выполняй его только как код на PHP, инициализировав массив $data нужными данными.
В моём самом последнем примере, который я приводил уже два раза - среднее время в десять раз больше минимального (при том, что почти все - не больше, чем 1.2*минимальное)
Мне очень влом объяснять, почему различные варианты изменения той функции не подходят, давай просто примем, как данность - её оптимизировать в обычном понимании нельзя. А минимальный код, показывающий её тормоза - в моём последнем примере. Как в случае с моим последним примером на порядок уменьшить время исполнения, не трогая при этом функциональную часть?
0.0550463199615
0.43668463821
0.0388622283936
0.978
Так что он не показателен. А то, что у тебя результаты другие - проблемы твоей системы, видимо.
Если их работы порядка, скажем, 2x%, то это нормально. Если разброс между максимумом и минимумом меньше, чем в 2-3 раза, то тоже нормально. Ты же говоришь, что 1% итераций съедает 90% времени, но на твоих примерах этого нет.У тебя среднее время работы 2% итераций, как видно из твоего результата - порядка 25х на каждую, и эти 2% итераций в сумме дают треть времени.
А разброс между минимумом и максимумом получается, опять же, больше, чем в 25 раз.
А то, что у тебя результаты другие - проблемы твоей системы, видимо.У меня результаты количественно другие, а не качественно.
А проблема, как видно по твоим результатам, остаётся и на твоей системе.
Может быть, у тебя за счёт каких-то дополнительных оптимизаций процессора/ОС масштаб проблемы меньше, но, тем не менее, на 2% итераций уходит времени всего в два раза меньше, чем на остальные 98% (а эти остальные 98% все укладываются по времени в 1.2*минимальное время).
У тебя среднее время работы 2% итераций, как видно из твоего результата - порядка 25х на каждую, и эти 2% итераций в сумме дают треть времени.А разброс между минимумом и максимумом получается, опять же, больше, чем в 25 раз.Ты это никак не изменишь. Среднее время работы одно и то же. А то, что нагрузка неравномерна по итерациям - это дело интерпретатора и операционки.
PS. Неправ. Более стабильно как раз минимальное время, а среднее скачет примерно на 50% туда-сюда. Это, видимо, из-за операционки и многозадачности, всё же.
PS. Неправ. Более стабильно как раз минимальное время, а среднее скачет примерно на 50% туда-сюда. Это, видимо, из-за операционки и многозадачности, всё же.Про что я и говорю.
Поэтому, логично назвать минимальное время - ожидаемым временем выполнения. А эти 1-2% итераций - глюками интерпретатора/ОС, которые увеличивают общее время выполнения в 1.5-10 раз.
Всё-таки, неужели нет способа бороться с этими глюками (переписывать код так, чтобы таких циклов не было/пользоваться более низкоуровневым языком - не борьба с глюками, а их обход, сопряжённый с большим гемором и, более того, не всегда допустимый).
Как, например, работают серъёзные приложения на php с большой нагрузкой - разработчики объявляют обязательным десятикратный запас по мощности (собирают кластер из десяти серверов, когда, по идее, должно хватить одного - да и его с большим запасом); избегают появления таких "плохих" циклов, где проявляются глюки; или всё-таки как-то избавляются от самих глюков?
дополнительные 100мс при выдае http-страницы никак не играют
Для конкретного пользователя — да. Но если у нас страница генерится 200 мс, а клики идут с частотой 100 мс, то достаточно много пользователей вообще не получат страницы.
где ты видел http-сервер, который теряет запросы? или хотя бы их выполняет только в одном потоке?
В 10 раз - это твои фантазии. У мну отклонение среднего времени при разных запусках отличается на 50%, ну максимум на 100%. Но никак не в 10 раз. И в этом нет ничего страшного. А 10-кратный запас прочности необходим.
где ты видел http-сервер, который теряет запросы? или хотя бы их выполняет только в одном потоке?Если запросы будут поступать быстрее, чем мы их обрабатывать, время между запросом и ответом будет увеличиваться пока не достигнет неразумных величин вроде минуты. После этого можно считать, что пользователь страницы не получил.
Во-вторых, провёл аналогичные замеры, чтобы посмотреть, насколько много сверхдолгих итераций. Вот использованый код:
<?
function test($n) {
return preg_replace("/\W/s","",$GLOBALS['str'].$n);
}
/////////////////////
function GetMicroTime
{
list($usec, $sec) = explode(" ",microtime;
return float)$usec + (float)$sec);
}
////////////////////
$str="";
for($i=0;$i<50;$i++) {
$str.=chr(mt_rand(0,255;
}
$tt=0;
$times2=array(8);
for($a=0; $a<8; $a++)
$times2[$a]=0;
$fulltime=0;
for($i=0;$i<100000;$i++)
{
$stime = GetMicroTime;
$tmp=test($i);
$tt+=12+$i*$i+ $i*36;
$sstime = GetMicroTime-$stime;
$fulltime+=$sstime;
if ($sstime<0.000001) $times2[0]++;
elseif ($sstime<0.00001) $times2[1]++;
elseif ($sstime<0.0001) $times2[2]++;
elseif ($sstime<0.001) $times2[3]++;
elseif ($sstime<0.01) $times2[4]++;
elseif ($sstime<0.1) $times2[5]++;
elseif ($sstime<1) $times2[6]++;
else $times2[7]++;
}
for($a=0; $a<8; $a++)
printf(" %d : %d <br>\n",$a, $times2[$a]);
printf("arerage: %f",$fulltime/100000.0);
?>
При запуске из командной строки скрипт работает ощутимо быстрее, чем через apache (php - so модуль).
Типовой результат:
//////////
0 : 0
1 : 0
2 : 99678
3 : 257
4 : 64
5 : 1
6 : 0
7 : 0
arerage: 0.000042
/////////////
$ time php tst2.php
0 : 0 <br>
1 : 0 <br>
2 : 99717 <br>
3 : 259 <br>
4 : 24 <br>
5 : 0 <br>
6 : 0 <br>
7 : 0 <br>
arerage: 0.000034
real 0m5.002s
user 0m4.440s
sys 0m0.380s
/////////////
Несложная прикидка даёт понять, что потери на неудачных операциях дают вклад менее 10 процентов, что несущественно.
значит сами дураки, что на такое кол-во запросов поставил такой компьютер.
речь-то идет не о том, может компьютер выполнить столько запросов или не может, а о том, что некоторые запросы могут выполняться на 100 мс больше
дополнительные 100мс при выдае http-страницы никак не играют"Большая нагрузка" - это не когда посетителю надо побыстрее получить страницу, а когда к ресурсу обращается куча пользователей.
Если страница генерится 10мс+дополнительные 100мс, а на ресурс каждую секунду происходит сто обращений - пользователи страничку не дождутся.
речь-то идет не о том, может компьютер выполнить столько запросов или не может, а о том, что некоторые запросы могут выполняться на 100 мс большеРечь идёт о том, что за счёт того, что 10мс-страница генерится на 100мс больше, мы можем выполнить не 100 запросов в секунду, а только 10.
2. сколько заходов на свой сайт в день ты планируешь?
"Большая нагрузка" - это не когда посетителю надо побыстрее получить страницу, а когда к ресурсу обращается куча пользователей.мне кажется, что в твоём коде ошибка, из-за неправильного использования фунции microtime. Я часто отлаживал и разгонял php код, с описанными эффектами сталкивался, но вклад от них - жалкие проценты. Проверь с моей функцией GetMicroTime
Если страница генерится 10мс+дополнительные 100мс, а на ресурс каждую секунду происходит сто обращений - пользователи страничку не дождутся.
Во-вторых,
<?выводит
$script_start_time=time;
$base=sqrt(sqrt(10;
function my_microtime {
list($usec, $sec) = explode(" ",microtime;
return float1000*$usec) + (float$sec-$GLOBALS['script_start_time'])*1000;
}
function test($n) {
return preg_replace("/\W/s","",$GLOBALS['str'].$n);
}
$str="";
for($i=0;$i<50;$i++) {
$str.=chr(mt_rand(0,255;
}
$times=array_fill(0,1000,0);
$times2=array_fill(0,20,0);
for($i=0;$i<1000;$i++) {
$stime=my_microtime;
$tmp=test($i);
$times[$i]=(my_microtime-$stime)*1000;
}
$min=10000;
foreach($times as $time) $min=($min>$time)?$time:$min;
foreach($times as $time) {
$t=$min;
for($i=0;IsSet($times2[$i]);$i++) {
$t*=$base;
if($time<$t) {
$times2[$i]++;
break;
}
}
}
echo "<pre>"; print_r($times2);
?>
[q]Array
(
[0] => 955
[1] => 12
[2] => 10
[3] => 1
[4] => 3
[5] => 1
[6] => 1
[7] => 5
[8] => 0
[9] => 3
[10] => 7
[11] => 0
[12] => 2
[13] => 0
[14] => 0
[15] => 0
[16] => 0
[17] => 0
[18] => 0
[19] => 0
)
1. т.е. хочешь сказать, что у тебя за секунду выполняется всего 10 запросов?Если обработка одного запроса занимает 100мс (без учёта дисковых итп операций - только чистые вычисления) - за секунду мы успеем обработать только десять запросов.
2. сколько заходов на свой сайт в день ты планируешь?Ну, например, 100*60*60*24.
мне кажется, что в твоём коде ошибка, из-за неправильного использования фунции microtime. Я часто отлаживал и разгонял php код, с описанными эффектами сталкивался, но вклад от них - жалкие проценты. Проверь с моей функцией GetMicroTime1) Чем они принципиально отличаются?
2) Если $str в моём примере большая - замедление действительно почти незаметно; оно заметно толко когда одна итерация занимает довольно мало времени.
1. у тебя очень плохой Http-сервер, который выполняет все запросы в одном потоке?
2. у тебя настолько все плохо, что на каждый запрос идет overhead в 100 мс?
мне кажется, что в твоём коде ошибка, из-за неправильного использования фунции microtime. Я часто отлаживал и разгонял php код, с описанными эффектами сталкивался, но вклад от них - жалкие проценты. Проверь с моей функцией GetMicroTimeКакая версия php?
1) Чем они принципиально отличаются?
2) Если $str в моём примере большая - замедление действительно почти незаметно; оно заметно толко когда одна итерация занимает довольно мало времени.
У меня
PHP 4.4.2 (cli) (built: Jun 13 2006 15:12:44)
Copyright (c) 1997-2006 The PHP Group
Zend Engine v1.3.0, Copyright (c) 1998-2004 Zend Technologies
Делаем echo "[".microtime(true)."]";
Получаем "[0.94445300 1160341966]"
Проверь, как это работает у тебя.
microtime
(PHP 3, PHP 4, PHP 5)
microtime — Return current Unix timestamp with microseconds
Description
mixed microtime ( [bool get_as_float] )
microtime returns the current Unix timestamp with microseconds. This function is only available on operating systems that support the gettimeofday system call.
When called without the optional argument, this function returns the string "msec sec" where sec is the current time measured in the number of seconds since the Unix Epoch (0:00:00 January 1, 1970 GMT and msec is the microseconds part. Both portions of the string are returned in units of seconds.
When get_as_float is given, and evaluates to TRUE, microtime will return a float.
?: The get_as_float parameter was added as of PHP 5.0.0.
for($i=0;$i<1000;$i++) {
$stime=my_microtime;
$tmp=test($i);
$stime2=(my_microtime-$stime)*1000;
$times[$i]=$stime2;
}
Тогда вывод становится (оригинальная версия у меня работает примерно так же, как и у тебя):
[0] => 993
[1] => 3
[2] => 1
[3] => 2
[4] => 1
[5] => 0
[6] => 0
[7] => 0
[8] => 0
[9] => 0
[10] => 0
[11] => 0
[12] => 0
[13] => 0
[14] => 0
[15] => 0
[16] => 0
[17] => 0
[18] => 0
[19] => 0
Причина этого - кривая работа php с массивами, из-за этого бывают реальные и серьёзные тормоза.
Ещё одна проблема, попробуй изменить цикл наВ смысле, посчитать разность отдельно, записать её в простую переменную, и только потом добавить содержимое этой переменной в массив?
Это ничего не меняет.
То, что у тебя стало лучше - попробуй запустить ещё раз, у меня тоже всё от раза к разу меняется, то ли из-за окружения, то ли из-за различных $str - иногда (но редко) действительно бывает, что все $times2 с индексом, большим 5, пусты.
Да, согласен, поторопился с выводами. Но с другой стороны - у тебя шаг 10^0.25, то есть 8 уровней - это торможение в 100 раз от нормы. Если оценить общий вклад, то получится (по крайней мере в моём варианте) на уровне 10 процентов. Так ли это много?
У меня в том посте $times2[12] получилось 2 - то есть, только за счёт $times2[12] набирается отклонение 200% от нормы.
Если ты сам говоришь, что на более длинных строках этот пример не тормозит...
Ну или не целиком, но допустим разбив его не 256 частей, а не на 1000 строк....
если тупят итерации - надо искать способ отказаться от них...
Может я конечно не в темуДа.
Повторяю ещё раз - советы как переписать функцию, не подходят. Вопрос в том, как избавиться от тормозов в текущем варианте, а не как всё полностью менять (и мб, получать тормоза в другом месте - ведь если сотня preg_replace'ов для длинных строк работает столько времени, как тысяча для мелких (и как десять тысяч для мелких, если нет тормозов) - не факт, что один preg_replace для длинной строки без тормозов должен работать в сто раз дольше, чем для мелкой).
если тупят итерации - надо искать способ отказаться от них...А гильотина - лучший способ от головной боли.
Сколько раз в этом треде я сказал, что мне надо именно улучшить то, что сейчас, а не переделывать его?
ЗЫ: Лучше всего, если тут вместо обсуждения гипотетического случая с шаблонами скажут, как ускорить работу вполне реального примера с предыдущей страницы.
т.е. вписать ее в исходники. и вызывать, давая ей например указатель на файл.
Хотя конечно другие варианты и не рассматриваются - но я бы все-же посмотрел для теста на каком размере оптимально работает preg_replace и куски именно такого размера ему бы и скармливал.
Т.к. полюбому у тебя будут в шаблоне строки, в которых не надо ничего подставлять, или же просто пустые строки, которые можно склеить в одну.
(В обоих предложениях я исхожу из мысли о том, что родные функции пхп работают априори быстрее, чем созданные пользователем, + т.к. они на С - их можно оптимизировать как того хотел автор.)
for($i=0;$i<1000;$i++){
$time_start=microtime(true);
$time=microtime(true) - $start_time;
if($time < 0.000001) $t[0]++
...
...
...
}
Даже так из 1000 итераций 10 бывает на 1 парядок больше чем все другие, и 1-2 итерации на 2 парядка. Так что ты от этого ни куда не денешся )
так имхо как раз и надо значит избавляться от цикла....
Во-вторых, твой ещё один альтернативный вариант не подходит - приложение должно быть кроссплатформенным, а возможности менять php на том сервере, на котором всё это работает, нет.
Так что ты от этого ни куда не денешся )Ну вот это не факт, может, есть всё-таки какие-нибудь средства в php, которые позволяют этого избежать, заключить этот цикл в какую-нибудь такую хрень, внутри которой ничего преываться не может.
Нет таких средств. Разве что ты свой интерпретатор напишешь.
Можешь кстати попробовать обратиться к разрабобтчикам, описать баг, или даже сам записаться в разработчики, и если баг исправишь - то твои труды включат в следубщий релиз php..
Благо в опенсорс проектах сделать это не трудно
![](/images/graemlins/smile.gif)
Можешь кстати попробовать обратиться к разрабобтчикам, описать багУ кого-нибудь есть опыт, как это делается?
Я имею в виду, не как заходить на bugs.php.net и жать "отправить", а как всё это описать...
Оставить комментарий
kruzer25
Как бороться с вот этим?При этом, times.txt выглядит так:
(***.php - просто 30кб кода)
Процессор во время загрузки, вроде бы, больше ничего не нагружает; свободной физической оперативной памяти к моменту запуска скрипта - 150МБ...