У меня есть PHP-скрипт, который я запускаю на Linux-машине Ubuntu. Сценарий порождает несколько процессов с помощью функции pcntl_fork()
и использует функцию pcntl_waitpid()
для регистрации их уничтожения. Он порождает эти ОЧЕНЬ часто (по моим оценкам, около 40-50 в секунду), но каждый из этих процессов немедленно завершается (я пробовал и exit()
, и posix_kill(${pid}, SIGKILL)
, но безрезультатно) . Скрипт работает нормально несколько секунд (в зависимости от 10 ~ 30 секунд), но неизбежно останавливается и перестает создавать «дочерние» процессы. Использование памяти на машине из-за сценария не увеличивается, но когда сценарий останавливается, процессор на машине медленно набирает обороты, пока я не принудительно завершу сценарий с помощью Ctrl-C. Каждый процесс предназначен для анализа строки текста и, наконец, сохранения ее в файл. В целях тестирования я просто выхожу из дочерних процессов, как только они создаются. В одном тесте около 1400 процессов были успешно запущены и остановлены до того, как скрипт завис, хотя, как я уже сказал, это диапазон.
Я понимаю, что у машины есть ulimit, но я полагаю, что читал, что он ограничивает количество одновременных процессов. Поскольку этот сценарий убивает дочерние процессы сразу после их создания, я не понимаю, что происходит. Вот результат моей текущей конфигурации ulimit (ulimit -a
):
core file size (blocks, -c) 0 data seg size (kbytes, -d) unlimited scheduling priority (-e) 0 file size (blocks, -f) unlimited pending signals (-i) 29470 max locked memory (kbytes, -l) 64 max memory size (kbytes, -m) unlimited open files (-n) 1024 pipe size (512 bytes, -p) 8 POSIX message queues (bytes, -q) 819200 real-time priority (-r) 0 stack size (kbytes, -s) 8192 cpu time (seconds, -t) unlimited max user processes (-u) 29470 virtual memory (kbytes, -v) unlimited file locks (-x) unlimited
Есть ли в PHP глобальный лимит, определяющий общее количество процессов, созданных во время выполнения скрипта? ** Имейте в виду, что эти дочерние процессы уничтожаются немедленно, поэтому я не верю, что это проблема создания неограниченного количества процессов, которые крадут системные ресурсы.
Вот исходный код:
Я инициализирую вилку этим
$this->process_control->fork(array($this, "${FUNCTION_NAME}"), array(STRING_LINE), false);
Функция разветвления процесса. В этом случае $ callback - это имя функции, вызываемой в соответствующем классе. $ params - это массив параметров для передачи функции, указанной в $ callback.
public function fork ($callback, $params = null, $hang = true) { $this->logger->write_log('log', "Entered fork function!"); // Evaluate the return value of the fork switch ($pid = pcntl_fork()) { case -1: // Failed $this->logger->write_log('error', "Could not fork!"); exit(1); break; case 0: // Child created succesfully $this->logger->write_log('log', "Entered child function!"); $this->logger->write_log('log', 'child ' . posix_getpid() . ' started'); if (empty($callback)) { $this->logger->write_log('warn', "Callback empty, nothing to do!"); exit(1); } if (is_array($callback) && is_array($params)) { if (!call_user_func_array($callback, $params)) { $this->logger->write_log('error', "Daemonized process returned false!"); exit(1); } else { exit(0); } } else { if (!call_user_func($callback, $params)) { $this->logger->write_log('error', "Daemonized process returned false!"); exit(1); } else { exit(0); } } break; default: // Parent $this->logger->write_log('log', "Entered parent function!"); if ($hang != true) { $this->wait($pid, false); } else { $this->wait($pid); } break; } } public function wait($p_id, $hang = true) { if ($hang) { $pid = pcntl_waitpid($p_id, $status); } else { $pid = pcntl_waitpid($p_id, $status, WNOHANG); } switch($pid) { case -1: case 0: $this->logger->write_log('log', "child exited"); break; default: $this->logger->write_log('log', "child $pid exited"); break; } }
Функция, которая фактически обрабатывает строки текста. Строки текста являются объектами JSON:
public function FUNCTION_NAME($line) { $this->logger->write_log('info', 'entered FUNCTION_NAME function'); $start_time = microtime(true); try { # check to see that the JSON line is not malformed $line_array = json_decode($line, true); if (!isset($line_array)) { throw new Exception('Could not successfully process line'); } # save the contents to disk if (!file_put_contents(FILE_NAME, $line, LOCK_EX)) { throw new Exception('file could not be saved'); } $this->logger->write_log('info', 'saved line'); return true; } catch (Exception $e) { $this->logger->write_log('error', $e->getMessage()); $this->logger->write_log('error', '----------------------------------------------------'); $this->logger->write_log('error', var_export($line, true)); $this->logger->write_log('error', '----------------------------------------------------'); file_put_contents(ERROR_SRC_FILE, $line, FILE_APPEND); return false; } }
Извините, если кода слишком много, дайте мне знать о любых вопросах
Each process is meant to parse a line of text and finally save it to a file
- для меня это не похоже на то, что требует совершенно нового процесса, почему вы думаете, что это способ сделать это? - person DaveRandom   schedule 16.04.2012popen()
илиproc_open()
, и передать данные другому процессу STDIN. Вы можете передать этот канал прямо в cURL, и тогда буферизация будет выполняться на вашей стороне, а не на удаленном сервере. Это очень долгий процесс / поток? - person DaveRandom   schedule 16.04.2012json_decode()
, а также похоже, что вы на самом деле ничего не делаете с данными в PHP-скрипте, просто проверяете его на синтаксически правильный JSON. В этом случае я полагаю, что Node будет лучшим инструментом для работы, поскольку он основан на Javascript и, следовательно, (я бы подумал) должен быть лучше / эффективнее при синтаксическом анализе JSON. Он также спроектирован так, чтобы быть асинхронным, поэтому он намного лучше подходит для этой задачи, чем PHP. - person DaveRandom   schedule 16.04.2012pcntl_waitpid
с помощьюWNOHANG
без какого-либо цикла для проверки после первого вызова, уверены ли вы, что процессы не находятся в состоянии зомби? Даже если выexit
от ребенка, родитель все равно должен очистить зомби-процессы после их завершения, что, похоже, не так, если$hang
неtrue
. - person netcoder   schedule 16.04.2012