Фоновый процесс PHP на BSD использует 100% CPU - PullRequest
0 голосов
/ 14 октября 2011

У меня есть PHP-скрипт, который запускается как фоновый процесс. Этот скрипт просто использует fopen для чтения из Twitter Streaming API. По сути, http-соединение, которое никогда не заканчивается. Я не могу опубликовать сценарий, к сожалению, потому что он проприетарный. Скрипт в Ubuntu работает нормально и использует очень мало процессора. Однако в BSD скрипт всегда использует почти 100% CPU. Скрипт работает отлично на обеих машинах и является точно таким же скриптом. Может кто-нибудь придумать что-то, что может указать мне правильное направление, чтобы это исправить? Это первый PHP-скрипт, который я написал для последовательного запуска в фоновом режиме.

Скрипт представляет собой бесконечный цикл, он считывает данные и каждую минуту записывает в файл json. Сценарий будет записывать в базу данных MySQL всякий раз, когда происходит переподключение, что обычно происходит после нескольких дней работы. Сценарий больше ничего не делает и не очень длинный. У меня мало опыта работы с BSD или написанием PHP-скриптов, которые запускают бесконечные циклы. Заранее спасибо за любые предложения, дайте мне знать, если это относится к другому StackExchange. Я постараюсь ответить на любые вопросы как можно быстрее, потому что я понимаю, что вопрос очень расплывчатый.

Ответы [ 3 ]

1 голос
/ 14 октября 2011

Не видя сценария, очень сложно дать вам окончательный ответ, однако вам нужно убедиться, что ваш сценарий ожидает данных соответствующим образом.Совершенно определенно , а не следует делать, это вызывать stream_set_timeout($fp, 0); или stream_set_blocking($fp, 0); в указателе вашего файла.

Базовая структура скрипта, выполняющая что-то подобное, которое должно избегать гонок, будетчто-то вроде этого:

// Open the file pointer and set blocking mode
$fp = fopen('http://www.domain.tld/somepage.file','r');
stream_set_timeout($fp, 1);
stream_set_blocking($fp, 1);

while (!feof($fp)) { // This should loop until the server closes the connection

  // This line should be pretty much the first line in the loop
  // It will try and fetch a line from $fp, and block for 1 second
  // or until one is available. This should help avoid racing
  // You can also use fread() in the same way if necessary
  if (($str = fgets($fp)) === FALSE) continue;

  // rest of app logic goes here

}

Вы также можете использовать sleep() / usleep(), чтобы избежать гонок, но лучший подход - полагаться на вызов функции блокировки для выполнения вашей блокировки.Если это работает в одной ОС, но не в другой, попробуйте явно установить режимы / поведение блокировки, как указано выше.

Если вы не можете заставить это работать с вызовом fopen(), передающим URL-адрес HTTP,это может быть проблема с реализацией оболочки HTTP в PHP.Чтобы обойти это, вы можете использовать fsockopen() и обрабатывать запрос самостоятельно.Это не так уж сложно, особенно если вам нужно только отправить один запрос и прочитать постоянный ответ потока.

1 голос
/ 14 октября 2011

Мне кажется, что одна из ваших функций кратковременно блокируется в Linux, но не в BSD. Не видя ваш сценарий, сложно получить конкретный пример, но я бы предложил добавить usleep() до следующей итерации цикла:

usleep(100000); //Sleep for 100ms

Вам не нужно долго спать ... достаточно, чтобы не использовать 100% CPU.

Редактировать: Так как вы упомянули, что у вас нет хорошего способа запустить это в фоновом режиме, я предлагаю проверить это руководство для "демонизации" вашего сценария . Включен некоторый удобный код для этого. Он может даже сделать файл в init.d для вас.

0 голосов
/ 14 октября 2011

Как выглядит код, который делает реальное чтение?Вы просто забиваете сокет, пока не получите что-то?

Один действительно эффективный способ справиться с этим - использовать расширение libevent , но это не для слабонервных.

...