PHP中的asynchronousshell exec
我有一个PHP脚本,需要调用一个shell脚本,但不关心输出。 shell脚本进行了大量的SOAP调用,并且执行起来很慢,所以我不想在等待回复时减慢PHP请求的速度。 实际上,PHP请求应该能够在不终止shell进程的情况下退出。
我研究了各种exec()
, shell_exec()
, pcntl_fork()
等函数,但是他们都没有提供我想要的东西。 (或者,如果他们这样做,我不清楚如何。)有什么build议吗?
如果它“不关心输出”,那么可以用&
来调用脚本的执行到后台进程吗?
编辑 – 纳入什么@ AdamTheHut评论到这个职位,你可以添加到调用exec
:
" > /dev/null 2>/dev/null &"
这会将stdio
(第一>
)和stderr
( 2>
)redirect到/dev/null
并在后台运行。
还有其他方法可以做同样的事情,但这是最简单的方法。
上述双重redirect的替代方法:
" &> /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是否有线程?
php-execute-a-background-process有一些很好的build议。 我觉得我很好,但我有点偏见:)
对于所有Windows用户:我find了一个运行asynchronousPHP脚本的好方法(实际上它几乎适用于所有的情况)。
它基于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
在Linux中,可以通过在命令末尾添加&符号来在新的独立线程中启动进程
mycommand -someparam somevalue &
在Windows中,您可以使用“启动”DOS命令
start mycommand -someparam somevalue
正确的方法(!)来做到这一点
- 叉子()
- setsid()
- 的execve()
fork fork,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
是一个像define('PHP_PATH', '/opt/bin/php5')
或类似的define('PHP_PATH', '/opt/bin/php5')
的const)
它通过命令行传递参数。 要在PHP中阅读它们,请参阅argv 。
我发现真正为我工作的唯一方法是:
shell_exec('./myscript.php | at now & disown')
使用一个名为fifo。
#!/bin/sh mkfifo trigger while true; do read < trigger long_running_task done
然后,只要你想开始长时间运行的任务,只需写一个换行符(非阻塞触发器文件。
只要你的input小于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过程组件对此很有用。
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仓库中是如何工作的。