当前位置:  开发笔记 > 编程语言 > 正文

PHP中的异步shell exec

如何解决《PHP中的异步shellexec》经验,为你挑选了7个好方法。

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

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



1> warren..:

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

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

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

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

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


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

" &> /dev/null &"


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

2> Czimi..:

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



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

3> LucaM..:

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



4> Darryl Hein..:

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

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

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

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



5> Mark Biek..:

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



6> Leo..:

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

mycommand -someparam somevalue &

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

start mycommand -someparam somevalue


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

7> 小智..:

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

    叉子()

    setsid()

    的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();


pcntl_fork()的问题是你不应该在Web服务器下运行时使用它,就像OP一样(此外,OP已经尝试过这个).
推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有