Я пытаюсь записать сценарий, который создает много разветвленных дочерних процессов с помощью pcntl_*
функции.
В основном существует единственный сценарий, который работает в цикле приблизительно в течение минуты, периодически опрашивая базу данных, чтобы видеть, существует ли задача, которая будет выполнена. Если существует один, это должно разветвить и выполнить задачу в отдельном процессе так, чтобы родитель не поддержался продолжительной задачей.
Так как возможно могло быть большим количеством задач, готовых быть выполненными, я хочу ограничить количество дочерних процессов, которые создаются. Поэтому я отслеживаю количество процессов путем постепенного увеличения переменной каждый раз, когда каждый создается (и затем приостановка, если существуют слишком многие), и затем постепенное уменьшение его в обработчике сигналов. Отчасти как это:
define(ticks = 1);
$openProcesses = 0; // how many we have open
$max = 3; // the most we want open at a time
pcntl_signal(SIGCHLD, "childFinished");
while (!time_is_up()) {
if (there_is_something_to_do()) {
$pid = pcntl_fork();
if (!$pid) { // I am the child
foo(); // run the long-running task
exit(0); // and exit
} else { // I am the parent
++$openProcesses;
if ($openProcesses >= $max) {
pcntl_wait($status); // wait for any child to exit
} // before continuing
}
} else {
sleep(3);
}
}
function childFinished($signo) {
global $openProcesses;
--$openProcesses;
}
Это работает в значительной степени хорошо большую часть времени, за исключением того, когда два или больше процесса заканчиваются одновременно - функцию-обработчик сигнала только называют однажды, который выводит мой счетчик. Причина этого объяснена "Анонимным" в примечаниях к руководству PHP:
Несколько детей возвращают меньше, чем число детей, выходящих в данный момент, о котором сигнализирует SIGCHLD, нормальное поведение для Unix (POSIX) системы. SIGCHLD мог бы быть считан, поскольку "один или несколько детей изменились, состояние - идут, исследуют Ваших детей и получают их значения состояния".
Мой вопрос - это: Как я исследую детей и получаю их состояние? Там какой-либо надежный путь состоит в том, чтобы проверить, сколько дочерних процессов открыто в любой момент времени?
Использование PHP 5.2.9
Вы можете попросить детей отправить SIGUSR1 для родителя при запуске, затем SIGUSR2 перед выходом. Другая вещь, с которой вы имеете дело при использовании примитивных сигналов, - это объединение их ядром, чего не происходит с сигналами RT. Теоретически можно объединить ЛЮБОЙ не-rt сигнал.
Вы можете реализовать какую-то простую блокировку с помощью sqlite, при которой только один дочерний элемент одновременно может иметь говорящую палку. Просто убедитесь, что дети обычно обрабатывают фатальные сигналы, чтобы они остались живы, чтобы освободить замок.