PHP中的异步shell exec

时间:2008-10-21 16:02:10

标签: php asynchronous shell

我有一个需要调用shell脚本的PHP脚本,但根本不关心输出。 shell脚本会进行大量的SOAP调用,并且完成起来很慢,因此我不想在等待回复时减慢PHP请求的速度。事实上,PHP请求应该能够在不终止shell进程的情况下退出。

我查看了各种exec()shell_exec()pcntl_fork()等功能,但它们似乎都没有提供我想要的功能。 (或者,如果他们这样做,我不清楚如何。)任何建议?

13 个答案:

答案 0 :(得分:208)

如果它“不关心输出”,是不是可以使用&来调用脚本的exec来处理该过程?

编辑 - 将@ AdamTheHut评论的内容纳入此帖子,您可以将其添加到exec的调用中:

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

这会将stdio(第一个>)和stderr2>)重定向到/dev/null并在后台运行。

还有其他方法可以做同样的事情,但这是最简单的阅读。


上述双重定位的替代方法:

" &> /dev/null &"

答案 1 :(得分:52)

我在上使用了,因为它确实开始了一个独立的过程。

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

答案 2 :(得分:20)

对于所有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

答案 3 :(得分:19)

在Linux上,您可以执行以下操作:

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

这将在命令提示符处执行命令,然后返回PID,您可以检查&gt; 0确保它有效。

这个问题类似:Does PHP have threading?

答案 4 :(得分:12)

php-execute-a-background-process有一些很好的建议。我觉得我很好,但我有偏见:)

答案 5 :(得分:7)

在Linux中,您可以通过在命令末尾添加&符来在新的独立线程中启动进程

mycommand -someparam somevalue &

在Windows中,您可以使用“启动”DOS命令

start mycommand -someparam somevalue

答案 6 :(得分:5)

正确的方法(!)是

  1. fork()的
  2. setsid()
  3. 的execve()
  4. fork forks,setsid告诉当前进程成为master(没有父进程),execve告诉调用进程被被调用进程替换。这样父母可以在不影响孩子的情况下辞职。

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

答案 7 :(得分:4)

我用过这个......

/** 
 * 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')或类似的)

它通过命令行传递参数。要在PHP中阅读它们,请参阅argv

答案 8 :(得分:3)

我发现真正为我工作的唯一方法是:

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

答案 9 :(得分:3)

我还发现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

的工作原理

答案 10 :(得分:1)

您还可以将PHP脚本作为守护程序 cronjob 运行:#!/usr/bin/php -q

答案 11 :(得分:1)

使用名为fifo。

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

然后,只要您想要启动长时间运行的任务,只需编写换行符(对阻止文件进行非阻塞。

只要您的输入小于PIPE_BUF并且它是单个write()操作,您就可以将参数写入fifo并让它们在脚本中显示为$REPLY。< / p>

答案 12 :(得分:0)

没有使用队列,你可以像这样使用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);