题
我有一个 PHP 脚本,需要调用 shell 脚本,但根本不关心输出。shell 脚本进行了大量 SOAP 调用,并且完成速度很慢,因此我不想在等待回复时减慢 PHP 请求的速度。事实上,PHP 请求应该能够在不终止 shell 进程的情况下退出。
我研究过各种 exec()
, shell_exec()
, pcntl_fork()
, , ETC。功能,但它们似乎都没有提供我想要的功能。(或者,如果他们这样做,我不清楚如何。)有什么建议吗?
解决方案
如果它“不关心输出”,是不是可以用&
来调用脚本的exec来为后台处理这个过程?
编辑 - 结合@ AdamTheHut 对此帖发表的评论,您可以将其添加到调用 exec
:
" > /dev/null 2>/dev/null &"
这会将 stdio
(第一个>
)和 stderr
( 2>
)重定向到 / dev / null
并在后台运行。
还有其他方法可以做同样的事情,但这是最简单的阅读。
上述双重定位的替代方法:
" &> /dev/null &"
其他提示
我在上使用了,因为它确实开始了一个独立的过程。
<?php
`echo "the command"|at now`;
?>
对于所有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 &");
}
}
在Linux上,您可以执行以下操作:
$cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = shell_exec($cmd);
这将在命令提示符处执行命令,然后返回PID,您可以检查&gt; 0确保它有效。
这个问题类似: PHP是否有线程化?
php-execute-a-background-process 有一些很好的建议。我觉得我很好,但我有偏见:)
在Linux中,您可以通过在命令末尾添加&符来在新的独立线程中启动进程
mycommand -someparam somevalue &
在Windows中,您可以使用“开始”按钮。 DOS命令
start mycommand -someparam somevalue
正确的方法(!)是
- 叉()
- 设置id()
- 执行()
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
是一个const定义,如 define('PHP_PATH','/ opt / bin / php5')
或类似的)
它通过命令行传递参数。要在PHP中阅读它们,请参阅 argv 。
我发现真正为我工作的唯一方法是:
shell_exec('./myscript.php | at now & disown')
我还发现有用的 Symfony Process Component 对此。
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 repo 中了解它的工作原理。
使用名为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);