#php #process #background #stdin #popen
#php #процесс #фон #stdin #popen
Вопрос:
Я пытаюсь использовать popen для запуска php-скрипта в фоновом режиме. Однако мне нужно передать (довольно большой) сериализованный объект.
$cmd = "php background_test.php >log/output.log amp;";
$fh = popen($cmd, 'w');
fwrite($fh, $data);
fclose($fh);
//pclose($fh);
Без амперсанда этот код выполняется нормально, но родительский скрипт будет ждать, пока дочерний не будет завершен. С помощью амперсанда STDIN не получает данных.
Есть идеи?
Ответ №1:
Вы можете попробовать разветвление, позволяющее дочернему процессу записывать данные, а основной скрипт продолжит работу в обычном режиме.
Что-то вроде этого
// Fork a child process
$pid = pcntl_fork();
// Unable to fork
if ($pid == -1) {
die('error');
}
// We are the parent
elseif ($pid) {
// do nothing
}
// We are the child
else {
$cmd = "php background_test.php >log/output.log";
$fh = popen($cmd, 'w');
fwrite($fh, $data);
fclose($fh);
exit();
}
// parent will continue here
// child will exit above
Подробнее об этом читайте здесь: https://sites.google.com/a/van-steenbeek.net/archive/php_pcntl_fork
Также проверьте функцию pcntl_waitpid() (zombies be gone) в документации php.
Комментарии:
1. Будьте очень осторожны с процессами-зомби, если вы собираетесь разветвлять свои скрипты. Альтернативой, которую вы можете рассмотреть, является диспетчер очередей, такой как Gearman.
Ответ №2:
Насколько я знаю, в php нет способа отправить процесс в фоновом режиме и продолжать передавать его стандартный идентификатор (но, возможно, я ошибаюсь). Здесь у вас есть два других варианта:
- Реорганизуйте ваш
background_test.php
, чтобы получить его ввод из командной строки и преобразовать вашу командную строку вphp background_test.php arg1 arg2 ... >log/output.log amp;
- Если ваш ввод довольно длинный, запишите его во временный файл, а затем передайте
background_test.php
скрипту этот файл, как в следующем коде
Пример для пункта 2:
<?
$tmp_file = tempnam();
file_put_content($tmp_file, $data);
$cmd = "php background_test.php < $tmp_name > log/output.log amp;";
exec($cmd);
Ответ №3:
Заставьте фоновые процессы прослушивать файл сокета. Затем откройте файл сокета из PHP и отправьте туда свои сериализованные данные. Когда ваш фоновый демон получает соединение через сокет, сделайте его разветвленным, считайте данные, а затем обрабатывайте.
Вам нужно будет немного почитать, но я думаю, что это лучший способ добиться этого. Под сокетом я подразумеваю файл сокета unix, но вы также можете использовать его по сети.
http://gearman.org / также является хорошей альтернативой, как упоминал @Joshua