PHP中的异步shell exec

Ada*_*utt 195 php shell asynchronous

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

我已经研究过的各种exec(),shell_exec(),pcntl_fork(),等功能,但他们都不似乎提供正是我想要的.(或者,如果他们这样做,我不清楚如何.)有什么建议吗?

war*_*ren 214

如果它"不关心输出",那么脚本的exec是否可以&通过后台进程调用?

编辑 - 结合@AdmTheHut评论到这篇文章的内容,您可以将其添加到以下呼叫exec:

" > /dev/null 2>/dev/null &"
Run Code Online (Sandbox Code Playgroud)

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

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


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

" &> /dev/null &"
Run Code Online (Sandbox Code Playgroud)

  • 这似乎有效,但它需要的不仅仅是一个&符号.我通过将">/dev/null 2>/dev/null&"附加到exec()调用来实现它.虽然我不得不承认我不确定那是做什么的. (11认同)
  • 只需注意"&>/dev/null&",如果你使用它,xdebug将不会生成日志.查看http://stackoverflow.com/questions/4883171/xdebug-start-trace-behaving-strangely/4888138#4888138 (9认同)
  • @MichaelJMulligan它关闭了文件描述符.也就是说,尽管提高了效率,事后看来,使用`/ dev/null`是更好的做法,因为写入封闭的FD会导致错误,而尝试读取或写入`/ dev/null`只是默默地无所作为. (4认同)
  • 重启apache时会破坏后台脚本......只要知道这个很长时间的工作,或者如果你的时间不顺利,你就会想知道为什么你的工作会消失...... (3认同)
  • 如果你想要火和忘记php和apache,绝对是你要走的路.很多生产Apache和PHP环境都会禁用pcntl_fork(). (2认同)
  • 关闭FD而不是将它们重新打开到/ dev/null会更有效:`<& - 1 <& - 2 <& - ` (2认同)
  • @fritzmg看看我的答案; 它适用于Windows和Unix:http://stackoverflow.com/a/40243588/1412157 (2认同)

Czi*_*imi 52

我曾经这一点,因为它是真正开始独立的进程.

<?php
    `echo "the command"|at now`;
?>
Run Code Online (Sandbox Code Playgroud)

  • 在某些情况下,这绝对是最好的解决方案.它是唯一一个让我从webgui发布"sudo reboot"("echo'睡眠3; sudo reboot'|现在")并完成渲染页面的工具..在openbsd上 (3认同)

Luc*_*caM 25

对于所有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 &");  
    }
} 
Run Code Online (Sandbox Code Playgroud)

原始代码来自:http://php.net/manual/en/function.exec.php#86329

  • @davidvalentino 正确,那很好!如果您想执行 PHP/Pyhton/NodeJS 脚本,您必须实际调用可执行文件并将脚本传递给它。例如:您不会在终端中输入“myscript.js”,而是写入“node myscript.js”。也就是说:**node** 是可执行文件,**myscript.js** 是要执行的脚本。可执行文件和脚本之间存在巨大差异。 (2认同)

Dar*_*ein 19

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

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

这将在命令提示符处执行命令,然后只返回PID,您可以检查> 0以确保其有效.

这个问题很相似:PHP有线程吗?


Mar*_*iek 13

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


Leo*_*Leo 7

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

mycommand -someparam somevalue &
Run Code Online (Sandbox Code Playgroud)

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

start mycommand -someparam somevalue
Run Code Online (Sandbox Code Playgroud)

  • 在Linux上,如果子进程尝试从子进程持有的打开文件句柄(即.stdout)读取,则父进程仍然可以阻塞,直到子进程完成运行,因此这不是一个完整的解决方案. (2认同)

phi*_*reo 6

我用过这个...

/** 
 * 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 &");
}
Run Code Online (Sandbox Code Playgroud)

(其中PHP_PATH定义为类似define('PHP_PATH', '/opt/bin/php5')或类似的常量)

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


小智 5

正确的方式(!)来做到这一点

  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();
Run Code Online (Sandbox Code Playgroud)

  • pcntl_fork()的问题是你不应该在Web服务器下运行时使用它,就像OP一样(此外,OP已经尝试过这个). (6认同)

Ant*_*ykh 5

我还发现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
Run Code Online (Sandbox Code Playgroud)

在其GitHub 存储库中查看它是如何工作的。

  • 警告:如果不等待,请求结束时进程将被终止 (2认同)