Асинхронная оболочка exec в PHP

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

Я просмотрел различные функции exec() , shell_exec() , pcntl_fork() и т. Д., Но ни один из них, похоже, не предлагает именно то, что я хочу. (Или, если они это делают, мне непонятно, как.) Любые предложения?

    Если он «не заботится о выходе», нельзя ли вызвать сценарий сценарию с помощью & для фонового процесса?

    EDIT – включив то, что @ AdamTheHut прокомментировал это сообщение, вы можете добавить это к вызову exec :

     " > /dev/null 2>/dev/null &" 

    Это перенаправит как stdio (first > ), так и stderr ( 2> ) в /dev/null и запустится в фоновом режиме.

    Есть и другие способы сделать то же самое, но это проще всего читать.


    Альтернатива вышеупомянутому двойному перенаправлению:

     " &> /dev/null &" 

    Я использовал для этого, поскольку это действительно начало независимого процесса.

     <?php `echo "the command"|at now`; ?> 

    В linux вы можете сделать следующее:

     $cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!'; $pid = shell_exec($cmd); 

    Это выполнит команду в команде prompty, а затем просто вернет PID, который вы можете проверить на> 0, чтобы убедиться, что он сработал.

    Этот вопрос аналогичен: имеет ли PHP поток?

    Для всех пользователей Windows: я нашел хороший способ запуска асинхронного PHP-скрипта (на самом деле он работает практически со всеми).

    Он основан на командах popen () и pclose (). И хорошо работает как в Windows, так и в Unix.

     function execInBackground($cmd) { if (substr(php_uname(), 0, 7) == "Windows"){ pclose(popen("start /B ". $cmd, "r")); } else { exec($cmd . " > /dev/null &"); } } 

    Исходный код: http://php.net/manual/en/function.exec.php#86329

    php-execute-a-background-process имеет несколько хороших предложений. Я думаю, что мой довольно хорошо, но я предвзятый 🙂

    В Linux вы можете запустить процесс в новом независимом потоке, добавив амперсанд в конце команды

     mycommand -someparam somevalue & 

    В Windows вы можете использовать команду «start» DOS

     start mycommand -someparam somevalue 

    правильный (!), чтобы это сделать

    1. вилка ()
    2. setsid ()
    3. execve ()

    fork forks, setsid сообщают текущему процессу стать ведущим (без родителя), execve сообщит, что вызывающий процесс будет заменен вызываемым. так что родитель может выйти, не затрагивая ребенка.

      $pid=pcntl_fork(); if($pid==0) { posix_setsid(); pcntl_exec($cmd,$args,$_ENV); // child becomes the standalone detached process } // parent's stuff exit(); 

    Я использовал это …

     /** * Asynchronously execute/include a PHP file. Does not record the output of the file anywhere. * Relies on the PHP_PATH config constant. * * @param string $filename file to execute * @param string $options (optional) arguments to pass to file via the command line */ function asyncInclude($filename, $options = '') { exec(PHP_PATH . " -f {$filename} {$options} >> /dev/null &"); } 

    (где PHP_PATH является PHP_PATH , определенной как define('PHP_PATH', '/opt/bin/php5') или аналогичный)

    Он передает аргументы через командную строку. Чтобы прочитать их на PHP, см. Argv .

    Единственный способ, который я нашел, который действительно работал для меня, был:

     shell_exec('./myscript.php | at now & disown') 

    Используйте названный fifo.

     #!/bin/sh mkfifo trigger while true; do read < trigger long_running_task done 

    Затем, когда вы хотите запустить долго выполняемую задачу, просто напишите новую строку (неблокируясь в файл триггера.

    Пока ваш ввод меньше, чем PIPE_BUF и это одна операция write() , вы можете записывать аргументы в fifo и показывать их как $REPLY в скрипте.

    Вы также можете запустить PHP-скрипт как демон или cronjob : #!/usr/bin/php -q

    без использования очереди, вы можете использовать proc_open() следующим образом:

      $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w") //here curaengine log all the info into stderror ); $command = 'ping stackoverflow.com'; $process = proc_open($command, $descriptorspec, $pipes); 

    Для этого я также нашел компонент Symfony Process .

     use Symfony\Component\Process\Process; $process = new Process('ls -lsa'); // ... run process in background $process->start(); // ... do other things // ... if you need to wait $process->wait(); // ... do things after the process has finished 

    Посмотрите, как это работает в репозитории GitHub .