Nano Hash - криптовалюты, майнинг, программирование

Как дождаться завершения процесса (а также дождаться соответствующих дочерних процессов) в PHP?

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

Я хочу вызвать эту программу на PHP.

Первоначально я использовал следующую стратегию (недопустимый php-код),

$process=proc_open("python xxx.py");
while (1) {
   sleep(5);
   $status = proc_get_status($process);
   if (!$status['running']) {
       exit_loop;
   }
   if (timeout) {
      proc_terminate($process, 9);
      exit_loop;
   }
}

Но затем я вскоре обнаружил ошибку, заключающуюся в том, что процесс фактически немедленно завершился, поскольку $status['running'] имеет значение false, но дочерний процесс все еще выполняется. Как на самом деле дождаться всех дочерних процессов?

Второй вопрос: я не смотрел proc_terminate, но я также заметил, что proc_terminate может работать не так, как я ожидал. Это потому, что $process — это bash, а не настоящий процесс python? Это также может быть связано с тем, что я завершил только родительский основной процесс, но не дочерний процесс.

Кто-нибудь посоветует мне, является ли приведенный выше код надежным PHP-кодом или нет? Есть ли лучший способ справиться с этим?

Спасибо.

======================

Больше информации,

  1. Я запускаю эту программу в оболочке (CLI) и не имею отношения к функциям CGI. Так что мне не нужно беспокоиться о max_execution_time.

  2. Я хочу дождаться дочерних процессов, созданных основным процессом, открытым proc_open, я создам в программе только один процесс.

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


Ответы:


1

proc_get_status может получить pid дочернего процесса

$status = proc_get_status($process);
$pid = $status["pid"]

затем вы можете использовать pcntl_waitpid, чтобы дождаться выхода дочернего процесса

pcntl_waitpid($pid, $child_status);

Но вам нужно, чтобы ваш php был скомпилирован с расширением pcntl.

См. Функции PCNTL.

ОБНОВЛЕНИЕ: Если вы хотите завершить дочерний процесс после тайм-аута

Во-первых: установите обработчик SIGALARM в свой основной процесс.

function term_proc() {
   // terminate your all child process
}

pcntl_signal(SIGALARM, term_proc);

Второй: используйте pcntl_alarm для отправки сигнала тревоги через несколько секунд.

pcntl_alarm($seconds)

Для 2-го вопроса proc_terminate будет работать независимо от того, какой процесс будет открыт.

08.12.2011

2

Если вы не собираетесь каким-либо образом взаимодействовать с порожденным процессом (например, перенаправляя его ввод или вывод), вы можете использовать system вместо proc_open. system будет ждать завершения порожденного процесса, поэтому нет необходимости проверять его время от времени.

Будьте осторожны: ожидание другого процесса может привести к завершению вашего скрипта из-за превышения max_execution_time. Это также может не подходить для внутреннего управления исполняющими блоками вашего веб-сервера.

Обновление: кажется, что вы хотите запустить процесс X, а затем подождать, пока все процессы, запускаемые самим процессом X, завершатся, прежде чем продолжить. Прошу прощения за плохие новости, но PHP не предназначен для такого типа работы, и то, что вам нужно, невозможно достичь с помощью стандартного PHP. Конечно, было бы возможно написать собственное расширение на C, раскрывающее эту функциональность, но, насколько я знаю, такого расширения нет в открытом доступе.

08.12.2011
  • Спасибо за ответы. Я запускаю эту программу в оболочке (CLI) и не имею отношения к функциям CGI. Так что мне не нужно беспокоиться о max_execution_time. Я хочу дождаться дочернего процесса, созданного основным процессом, открытым proc_open, я создам в программе только один процесс. Наконец, программа python, которая использует какую-то другую программу, которая может зависать очень долго, поэтому я хочу проверить тайм-аут и завершить ее. System() может не завершиться по тайм-ауту, я думаю? 08.12.2011
  • @ user534498: А, понятно. Обновил ответ, но, к сожалению, то, что вы хотите сделать, невозможно сделать в PHP (по крайней мере, без специального расширения PHP). 08.12.2011

  • 3

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

    • cgroups обеспечивает достаточный механизм для systemd для отслеживания всех дочерних процессов, запущенных с одного начального execve(2) вызова .

      Хотя вы можете использовать cgroups самостоятельно, я мало что знаю о последствиях попыток использовать cgroups для управления процессами, в то время как systemd или libvirt или другие инструменты могут делать аналогичные вещи. (Это мое невежество больше, чем ограничение cgroups — возможно, оно прекрасно справляется с этим. Я люблю мечтать.)

    • Откройте pipe(2) в своем процессе и дайте конец чтения pipe(7), созданного дочернему процессу, в файловом дескрипторе, достаточно высоком, чтобы он не использовался «случайно». (вероятно, подойдет dup2(fd[0], 20).) Убедитесь, что другие программы не закрывают неожиданные файловые дескрипторы. Установите флаг O_NONBLOCK на конец записи (fd[1]) с помощью команды F_SETFL fcntl(2).

      Периодически пытайтесь записать байт в канал. В конце концов, вы либо получите возврат ошибки EPIPE, указывающий, что конец чтения был закрыт всеми дочерними элементами, ЛИБО вы получите возврат ошибки с errno, установленным на EAGAIN, означающим, что канал заполнен и все еще есть ребенок бежит.

    08.12.2011
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..