Подтвердить что ты не робот

Эхо-контент иногда занимает очень много времени

У меня есть script, который строит мою веб-страницу в одной строке ($ content), а затем повторяет ее пользователю.

Мой script выглядит следующим образом:

$time1= microtime(true);
$content = create_content();
$content_time=(microtime(true)-$time1)

$time = microtime(true);
echo $content;
$echo_time = (microtime(true)-$time);

Теперь $content_time всегда хорошо под 0,5 с, поэтому нет проблем. Однако несколько раз в день $echo_time намного превышает одну секунду и может даже увеличиваться до 15 секунд. Контент не очень большой, около 10-20 кб, а время, когда это происходит, совершенно случайно, поэтому оно не в трудное время и даже происходит посреди ночи.

Кто-нибудь знает, что это может быть?

ИЗМЕНИТЬ Сайт размещен на удаленном выделенном сервере и размещает только этот сайт. Существует база данных, но, как я уже сказал, $content_time составляет менее 1 секунды, так что эта функция не может быть задержкой.

Когда время моего сайта превышает определенное значение (скажем, 5 с), я регистрирую его. Иногда у Googlebots возникают такие проблемы, поэтому я не думаю, что они используют коммутируемое соединение:)

4b9b3361

Ответ 1

Позвольте сузить проблему и отбросить некоторые вещи...

В вопросе вы указываете, что вы эхо 10-15kb. Это значительная сумма независимо от того, как она буферизована для вывода - помните, что php - это один поток, как только вы очищаете свой буфер, вам нужно дождаться, когда все выходные данные будут выполнены через оболочку или HTTP до того, как будет продолжен script. В конце концов, он должен будет очистить внутренний буфер, прежде чем продолжить эхо. Чтобы получить хорошее время без сброса над головой эха

Попробуйте заменить

$time = microtime(true);
echo $content;
$echo_time = (microtime(true)-$time);

С

ob_start();
$time = microtime(true);
echo $content;
$echo_time = (microtime(true)-$time);
ob_clean();

Это будет эхо в буфер, но на самом деле не вытолкнет его через HTTP или что-то еще. Это должно дать вам "реальное" время команды эха без каких-либо проблем, отправляя то, что в буфере.

Если echo_time сжимается, у вас есть проблема с транспортом, с которой вы можете справиться как можно лучше с буферизацией.

Если echo_time все еще велико, вам нужно начать копаться в коде PHP C.

В любом случае вы намного ближе к поиску вашей проблемы и решению

Ответ 2

Из http://wonko.com/post/seeing_poor_performance_using_phps_echo_statement_heres_why

Этот старый отчет об ошибке может пролить свет. Короче говоря, использование эха для отправки больших строк в браузер приводит к ужасной производительности из-за способа "Алгоритм Нэглса" заставляет буферизировать данные для передачи по TCP/IP.

Решение? Простая трехлинейная функция, которая разбивает большие строки на более мелкие куски, прежде чем повторять их:

function echobig($string, $bufferSize = 8192) { 
    $splitString = str_split($string, $bufferSize);

    foreach($splitString as $chunk) { echo $chunk; }
}

Играйте с размером буфера и посмотрите, что лучше всего подходит для вас. Я обнаружил, что 8192, помимо хорошего круглого номера, казался хорошим размером. Некоторые другие ценности тоже работают, но я не смог распознать образец после нескольких минут возиться, и, очевидно, есть математика на работе, которую я не хочу пытаться выяснить.

Кстати, производительность также возникает при использовании функций управления выводами PHP (ob_start() и друзей)

Следуя комментарию OPs, который он попробовал, я также нашел следующее на PHP.net, предлагая, что str_split также может быть пустой тратой ресурсов, а функция echobig может быть оптимизирована далее, используя следующий код:

function echobig($string, $bufferSize = 8192) {
  // suggest doing a test for Integer & positive bufferSize
  for ($chars=strlen($string)-1,$start=0;$start <= $chars;$start += $bufferSize) {
    echo substr($string,$start,$buffer_size);
  }
}

Пробовали ли вы использовать script с помощью CLI, а не через Apache?

Ответ 3

Вы можете сделать это лучше, используя выходные буферы. На базовом уровне вы используете ob_start(), чтобы начать запись в выходной буфер, а затем ob_end_flush(), чтобы отправить его клиенту. Вот что php.net должен сказать о ob_start():

Эта функция включит буферизацию вывода. В то время как буферизация вывода активна, выходной сигнал не выводится из script (кроме заголовков), вместо этого вывод сохраняется во внутреннем буфере. Содержимое этого внутреннего буфера может быть скопировано в строковую переменную с помощью ob_get_contents(). Чтобы вывести то, что хранится во внутреннем буфере, используйте ob_end_flush().

Ответ 4

У меня была такая же проблема в прошлом, очень похожая на вашу. Я обнаружил, что эта проблема может быть вызвана медленными клиентами. Если клиент взял половину страницы и затем зависает, php будет ждать, пока клиент будет готов, а затем отправит остальную часть содержимого. Таким образом, это может быть не проблема на вашей стороне.

Обновление:

Вы можете попробовать выполнить следующие сценарии на своем сервере, чтобы проверить это. Этот script помещается на ваш сервер и называет его echo.php:

<?php
$time_start = time();
echo str_repeat("a", 200000);
echo "\nThis script took: " . (time() - $time_start) . " sec";

Затем введите его с помощью script (измените example.com в свой домен):

<?php
$fp = fsockopen("example.com", 80, $errno, $errstr, 30);
if (!$fp) {
    echo "$errstr ($errno)<br />\n";
} else {
    $out = "GET /echo.php HTTP/1.1\r\n";
    $out .= "Host: example.com\r\n";
    $out .= "Connection: Close\r\n\r\n";
    fwrite($fp, $out);
    while (!feof($fp)) {
        echo fgets($fp, 5000);
        sleep(1);
    }
    fclose($fp);
}

У меня echo.php работает 27 секунд. Когда я удаляю строку sleep(1), echo.php занимает всего 2 секунды для запуска.

Ответ 5

Как невозможно рассказать вам причину, не зная тела вашей функции create_content(), я предлагаю вам добавить больше функций "регистрации времени" непосредственно внутри этой функции. Внесение включенного кода все меньше и меньше, вы, наконец, найдете линию, которая вызывает отставание. Знание конкретной строки поможет вам понять проблему (база данных, загрузка машины, проблемы с подключением к внешним службам,...).

Ответ 6

Есть ли у вас какое-то время() или for() в вашем script? Если это так, вы должны проверить, не противоречат ли эти значения чему-либо, иногда я забыл об этом самостоятельно, а мой script также работал около 30 секунд.

Ответ 7

Моя догадка заключается в том, что действие доступа к этому большому числу строк занимает приличный объем памяти для нескольких целей. Поскольку PHP - сбор мусора, память берется до тех пор, пока сборщик мусора не будет запущен, а затем он освободится. Я предполагаю, что несколько запросов на сохранение содержимого в строковой переменной приводят к быстрому заполнению энергозависимой памяти (ОЗУ). Затем несколько раз в день вы начинаете поражать лимит, вызывая более медленное время загрузки. Сборщик мусора попадает, и все возвращается в норму.

Ответ 8

Если это выделенный сервер, пожалуйста, войдите в консоль и посмотрите, какой процесс использует много процессорного времени при создании контента. Его очень сложно сказать, когда мы не можем видеть код. Возможно, вам просто нужны индексы в базе данных, или, возможно, вам нужно удалить некоторые индексы.

Вы также можете проверить файлы журнала httpd и mysqld.