Я читал другие вопросы по SO с аналогичным названием, но этот вопрос не об этом. Я знаю, КАК выполнить сценарий PHP из другого сценария PHP. Проблема в том, что когда я это делаю, он использует слишком много процессора. Я хотел бы знать, как это уменьшить.

У меня есть простой скрипт, похожий на фронт-контроллер, который называется index.php. Он обрабатывает запросы GET от клиента и, в зависимости от переданного параметра «действие», отправляет запрос в соответствующий файл для его обработки. Например, это запрос клиента:

xhttp.open("GET", serverURL + "?action=doSomething" + "&userID=" + user.ID + "&time=" + lastServerTime, true);

Index.php имеет массив, который отображает параметр "действие" в соответствующий файл:

exec('php ' . $url_map[$action] . ' "' . $parameter1 . '"' . ' "' . $parameter2 . '" 2>&1', $output, $return_value);

В целях тестирования я создал PHP-скрипт, который ничего не делает, кроме измерения загрузки ЦП и вывода его в файл журнала:

<?php

function varDumpToFile($parameter1) {
    $file = 'log.txt';
    $dump = $parameter1;

    $output = print_r($dump, true);

    file_put_contents($file, $output, FILE_APPEND | LOCK_EX);
}

varDumpToFile(`ps -eo pcpu,pid,user,args --no-headers| sort -t. -nk1,2 -k4,4 -r |head -n 5`);

?>

Это создает файл журнала, который выглядит следующим образом:

9.0 3123052 user   /opt/cpanel/ea-php56/root/usr/bin/php cputest.php 10 147424 1537625595

Ясно, что PHP-скрипт не должен занимать 9% CPU. Для сравнения я запустил тот же сценарий, обращаясь к нему напрямую через запрос GET:

0.1 3186198 user   lsphp:ic_html/dev/php/cputest.php

0,1% больше нравится. Но почему вызов этого сценария PHP из другого сценария PHP использует так много ресурсов процессора? Причина в том, что мне нужно выполнить «новый экземпляр» PHP, когда я запускаю PHP, что имеет много накладных расходов? Если да, то есть ли способ выполнить сценарий PHP, используя «уже запущенный» экземпляр PHP? Или есть другой способ сделать это?

4
Arj 23 Сен 2018 в 03:45

2 ответа

Лучший ответ

Я всегда говорю: «Если сомневаетесь, посмотрите исходный код PHP». Здесь, например. При выполнении exec вы должны разделить процесс, создать новый поток, прочитать из входного буфера и т. Д.

Кроме того, хотя PHP является скомпилированным языком, для вновь разветвленного процесса вы должны запустить компилятор кода операции, чтобы сгенерировать коды операций (инструкции, похожие на байт-код Java), а затем выполнить их. Вы можете прочитать об этом здесь. В итоге вы запускаете компилятор дважды, для каждой вилки отдельно.

Стоит 9% вашего процессора? Я понятия не имею. Может быть. Может быть нет. Кто знает.

«Лучшее решение»? Обновите PHP до последней версии. PHP 5.6 больше не поддерживается, и обновления безопасности прекратятся через 3 месяца. Еще лучшее решение - сохранить нормальный объектно-ориентированный и поддерживаемый код без использования exec. ИМО, это нормально играть с exec, как и вы. Но если это ваш производственный код, я молюсь за души тех, кто будет поддерживать ваш код после вас.

4
Alex Karshin 23 Сен 2018 в 01:22

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

Не только накладные расходы на выполнение новых процессов, но и среда выполнения также будет совершенно другой. Если вы посмотрите в свою конфигурацию php, там будет несколько файлов php.ini, по одному для каждой конкретной среды. Это означает, что в одной среде могут быть включены разные модули или разная конфигурация. Нередко для скриптов cli max_execution_time или memory_limit установлено неограниченное значение. Это может повлиять на использование ресурсов на вашем сервере, но это также проблема.

Кроме того, поскольку ваши сценарии будут выполняться в совершенно новом процессе в другой среде выполнения, у него не будет доступа к некоторым переменным (например, $_SERVER или $_POST) или таким возможностям, как отправка заголовков.

И есть вещь, называемая разделяемой памятью. Как упоминает @Alex, скрипты должны быть скомпилированы. Если у вас включен кеш-код операции (что необходимо), байт-код кэшируется при компиляции, и этот процесс компиляции можно пропустить, если полученный байт-код уже существует. Чтобы это работало, вам необходимо иметь постоянно работающий процесс, который может хранить эту память. Если вы создаете новый процесс, он не может получить доступ к этой общей области и должен выполнять компиляцию самостоятельно.

2
msg 23 Сен 2018 в 02:36