Самый простой способ начать новый процесс / поток в PHP - PullRequest
10 голосов
/ 18 декабря 2011

Сценарий:

  1. Общий хостинг, поэтому нет возможности устанавливать новые расширения + нет CRON
  2. Поданный запрос должен выполнить некоторые тяжелые процессы.
  3. Я хочу, чтобы ответ клиенту проходил как можно быстрее, а тяжелая работа продолжалась немедленно, но не остановила клиента.
  4. может быть в новом потоке (если это возможно), также нет проблем с запуском нового процесса.

Каков наилучший способ сделать это?

Ответы [ 5 ]

11 голосов
/ 18 декабря 2011

Вкл. * Nix:

exec('/path/to/executable > /dev/null 2>&1 &');

В Windows:

$WshShell = new COM('WScript.Shell'); 
$oExec = $WshShell->Run('C:\path\to\executable.exe', 0, false);

Оба из них будут порождать новый процесс, который будет выполняться синхронно, полностью отключенный от родителя.Пока ваш хост позволяет вам это делать.

2 голосов
/ 09 октября 2018

В дополнение к ответу @ DaveRandom: на самом деле не нужно для перенаправления STDERR на STDOUT2>&1).

Однако вам нужно перенаправить STDOUT, если вы хотите предотвратить зависание родительского процесса в ожидании завершения дочернего процесса. Это необходимо, потому что exec вернет последнюю строку вывода дочернего процесса, поэтому ему нужно дождаться закрытия дочернего элемента STDOUT.

Это не значит, что вам нужно перенаправить его на /dev/null. Вы можете перенаправить его в другой файл или даже в другой дескриптор файла (например, STDERR: 1>&2).

  • exec('/path/to/executable'): запустит новый процесс и дождется его завершения (т. Е. Блокировки родительского процесса).
  • exec('/path/to/executable &'): в основном то же, что и выше.
  • $pid = exec('/path/to/executable > /dev/null & echo $!'): запустит процесс в фоновом режиме, когда дочерний и родительский процессы будут выполняться параллельно. Вывод /path/to/executable будет отброшен, а $pid получит PID дочернего процесса.

Использование 2>&1 на самом деле не является необходимым, потому что exec игнорирует STDERR дочернего процесса. Это также, вероятно, нежелательно, потому что будет труднее находить некоторые ошибки, потому что они будут просто тихо выброшены. Если вы опустите 2>&1, вы можете передать STDERR родительского процесса в какой-нибудь файл журнала, который можно проверить позже, если что-то пойдет не так:

php /path/to/script.php 2>> /var/log/script_error.log

Используя вышеописанное для запуска сценария, запускающего дочерние процессы, все, что script.php и любого дочернего процесса, записывающего в STDERR, будет записано в файл журнала.

2 голосов
/ 20 декабря 2012

Вы можете зайти в Google по ключу: php продолжить обработку после закрытия соединения.

Следующие ссылки, относящиеся к вашей проблеме:

Вы можетеиспользуйте команду принадлежать, чтобы продолжить выполнение без прерывания пользователя

ignore_user_abort(true);
set_time_limit(0);

Вы используете fastcgi_finish_request для предупреждения клиента о прекращении вывода ответа.И ваши сценарии будут продолжать выполняться.

Пример:

// redirecting...
ignore_user_abort(true);
set_time_limit(0);
header("Location: ".$redirectUrl, true);
header("Connection: close", true);
header("Content-Length: 0", true);
ob_end_flush();
flush();
fastcgi_finish_request(); // important when using php-fpm!

sleep (5); // User won't feel this sleep because he'll already be away

// do some work after user has been redirected
1 голос
/ 18 декабря 2011

В PHP нет потоков.Вы можете обмануть, отправив обратно HTML-страницу, которая запускает Ajax-вызов, чтобы начать тяжелый процесс в новом запросе.Но если это виртуальный хостинг, я предполагаю, что вы быстро достигнете ограничений по объему памяти, времени или использованию процессора, установленных вашим хостинг-провайдером.

0 голосов
/ 26 июля 2012
$WshShell = new COM('WScript.Shell');
$oExec    = $WshShell->Run('C:\xampp\php\php.exe C:\xampp\htdocs\test.php -a asdf', 0, true);

Невозможно передать argv в test.php.

var_dump($argv);
...