php asynchronous task
Ejecutor de shell asincrónico en PHP (13)
En Linux, puede iniciar un proceso en un nuevo hilo independiente agregando un ampersand al final del comando
mycommand -someparam somevalue &
En Windows, puede usar el comando "start" de DOS
start mycommand -someparam somevalue
Tengo un script PHP que necesita invocar un script de shell pero no le importa en absoluto el resultado. El script de shell realiza varias llamadas SOAP y tarda en completarse, por lo que no quiero ralentizar la solicitud de PHP mientras espera una respuesta. De hecho, la solicitud de PHP debería poder salir sin finalizar el proceso de shell.
He shell_exec()
pcntl_fork()
funciones de exec()
, shell_exec()
, pcntl_fork()
, etc., pero ninguna parece ofrecer exactamente lo que quiero. (O, si lo hacen, no me queda claro cómo). ¿Alguna sugerencia?
En Linux, puedes hacer lo siguiente:
$cmd = ''nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!'';
$pid = shell_exec($cmd);
Esto ejecutará el comando en el comando pronpty y luego simplemente devolverá el PID, que puede verificar para> 0 para asegurarse de que funcionó.
Esta pregunta es similar: ¿PHP tiene enhebrado?
La única forma que encontré que realmente funcionó para mí fue:
shell_exec(''./myscript.php | at now & disown'')
Para todos los usuarios de Windows: encontré una buena manera de ejecutar un script PHP asíncrono (en realidad funciona con casi todo).
Se basa en los comandos popen () y pclose (). Y funciona bien tanto en Windows como en Unix.
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
Código original de: http://php.net/manual/en/function.exec.php#86329
Si "no le importa la salida", ¿no podría llamarse al ejecutor del script con el proceso &
to background?
EDITAR - incorporando lo que @ comentó a esta publicación, puede agregar esto a una llamada al exec
:
" > /dev/null 2>/dev/null &"
Eso redireccionará stdio
(first >
) y stderr
( 2>
) a /dev/null
y se ejecutará en segundo plano.
Hay otras maneras de hacer lo mismo, pero este es el más simple de leer.
Una alternativa a la doble redirección anterior:
" &> /dev/null &"
También encontré el componente de proceso Symfony útil para esto.
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
Vea cómo funciona en su repositorio GitHub .
También puede ejecutar el script PHP como daemon o cronjob : #!/usr/bin/php -q
Usé esto ...
/**
* 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 &");
}
(donde PHP_PATH
es un const definido como define(''PHP_PATH'', ''/opt/bin/php5'')
o similar)
Pasa argumentos a través de la línea de comando. Para leerlos en PHP, vea argv .
Usa un nombre fifo.
#!/bin/sh
mkfifo trigger
while true; do
read < trigger
long_running_task
done
Luego, cuando quiera iniciar la tarea de larga ejecución, simplemente escriba una nueva línea (sin bloqueo al archivo desencadenante).
Siempre que su entrada sea menor que PIPE_BUF
y se PIPE_BUF
de una sola operación de write()
, puede escribir argumentos en la fifo y hacer que aparezcan como $REPLY
en la secuencia de comandos.
Utilicé para esto, ya que realmente está comenzando un proceso independiente.
<?php
`echo "the command"|at now`;
?>
la forma correcta (!) de hacerlo es
- tenedor()
- setsid ()
- execve ()
fork tenedores, setsid le dice al proceso actual que se convierta en uno maestro (sin padre), y luego le dice al proceso de llamada que sea reemplazado por el llamado. para que el padre pueda dejar de fumar sin afectar al niño.
$pid=pcntl_fork();
if($pid==0)
{
posix_setsid();
pcntl_exec($cmd,$args,$_ENV);
// child becomes the standalone detached process
}
// parent''s stuff
exit();
sin cola de uso, puede usar proc_open()
esta manera:
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "w") //here curaengine log all the info into stderror
);
$command = ''ping .com'';
$process = proc_open($command, $descriptorspec, $pipes);
php-execute-a-background-process tiene algunas buenas sugerencias. Creo que el mío es bastante bueno, pero estoy predispuesto :)