Отображение контента иногда занимает очень много времени - PullRequest
12 голосов
/ 03 января 2012

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

Мой скрипт выглядит так:

$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 с) Я регистрирую это.Иногда кажется, что даже у роботов Google есть эти проблемы, поэтому я не думаю, что они используют коммутируемое соединение:)

Ответы [ 8 ]

10 голосов
/ 14 февраля 2012

Давайте сузим проблему и выделим некоторые вещи ...

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

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

$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, не беспокоясь об отправке того, что находится в буфере.

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

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

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

5 голосов
/ 11 февраля 2012

С http://wonko.com/post/seeing_poor_performance_using_phps_echo_statement_heres_why

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

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

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

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

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

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

После комментария OP, что он попробовал это, я также нашел следующее на 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);
  }
}

Вы пытались запустить свой сценарий, используя CLI, а не через Apache?

1 голос
/ 11 февраля 2012

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

Обновление:

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

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

Затем загрузите его с помощью этого скрипта (измените 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 секунды.

1 голос
/ 03 января 2012

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

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

0 голосов
/ 18 февраля 2012

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

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

0 голосов
/ 17 февраля 2012

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

0 голосов
/ 12 февраля 2012

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

0 голосов
/ 11 февраля 2012

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...