有没有办法在不等待命令完成的情况下使用 shell_exec ?
Posted
技术标签:
【中文标题】有没有办法在不等待命令完成的情况下使用 shell_exec ?【英文标题】:Is there a way to use shell_exec without waiting for the command to complete? 【发布时间】:2010-11-04 10:15:30 【问题描述】:我有一个需要在后台运行的进程密集型任务。
用户点击一个页面,php脚本运行,最后,根据一些条件,如果需要,它必须运行一个shell脚本,例如:
shell_exec('php measurePerformance.php 47 844 email@yahoo.com');
目前我使用shell_exec,但是这需要脚本等待输出。有什么方法可以执行我想要的命令而不等待它完成?
【问题讨论】:
注意:该进程必须立即启动,因此不能选择 cron。 请注意:确保页面不会被所有人(搜索引擎/欺诈用户)访问,如果您在共享环境中,所有脚本的执行时间(特别是 php !)可能是有限的。无论如何,您可能想看看 set_time_limit/php.ini。 php execute a background process的可能重复 【参考方案1】:添加怎么样。
"> /dev/null 2>/dev/null &"
shell_exec('php measurePerformance.php 47 844 email@yahoo.com > /dev/null 2>/dev/null &');
请注意,这也摆脱了 stdio 和 stderr。
【讨论】:
没有。没有副作用。如果您有时决定想要进程的 stdio 或 stderr 输出,请考虑 ***.com/questions/45953/… 问题:这只是丢弃输出,对吗? PHP 在继续执行之前是否仍然等待进程完成,还是会触发并忘记? 是丢弃。是的,一发不可收拾 注意:在其他答案中看到的> /dev/null 2>&1 &
是此处给出的> /dev/null 2>/dev/null &
的简洁形式。这基本上是说“将 STDERR (2) 重定向到与 STDOUT (&1) 相同的位置”。
我通常通过添加 echo $! 来获取运行脚本的 PID! >> /tmp/pid.txt 在 exec 命令的末尾,但是通过将输出和错误重定向到 /dev/null,没有更多的 pid 文件:你们中的任何人都可以在不等待输出的情况下获得 exec 启动的脚本的 PID 吗?
【参考方案2】:
这将执行一个命令并与正在运行的进程断开连接。当然,它可以是您想要的任何命令。但是对于测试,您可以使用 sleep(20) 命令创建一个 php 文件。
exec("nohup /usr/bin/php -f sleep.php > /dev/null 2>&1 &");
【讨论】:
这个好还是shell_exec好? 嗨,我可以使用这个 shell_exec("nohup /usr/bin/php -f example.com/notifications/sendnotifications_async > /dev/null 2>&1 &"); 为什么bothnohup
和 &
?【参考方案3】:
您还可以立即将输出返回给客户端,然后继续处理您的 PHP 代码。
这是我用于长时间等待的 Ajax 调用的方法,它不会对客户端产生任何影响:
ob_end_clean();
ignore_user_abort();
ob_start();
header("Connection: close");
echo json_encode($out);
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// execute your command here. client will not wait for response, it already has one above.
你可以在这里找到详细的解释:http://oytun.co/response-now-process-later
【讨论】:
Ops...我在这里唤醒了一个僵尸问题,我还没有意识到。但这一点信息可能对其他人有益。 这与 shell_exec 没有任何关系 我正在使用它进行本地到远程测试。在远程本身上,我使用 shell_exec。谢谢 :)【参考方案4】:在 Windows 2003 上,为了不等待就调用另一个脚本,我使用了这个:
$commandString = "start /b c:\\php\\php.EXE C:\\Inetpub\\wwwroot\\mysite.com\\phpforktest.php --passmsg=$testmsg";
pclose(popen($commandString, 'r'));
这仅在更改 cmd.exe
的权限后才有效 - 为 IUSR_YOURMACHINE
添加读取和执行(我还将写入设置为拒绝)。
【讨论】:
【参考方案5】:使用 PHP 的popen
命令,例如:
pclose(popen("start c:\wamp\bin\php.exe c:\wamp\www\script.php","r"));
这将创建一个子进程,脚本将在后台执行,无需等待输出。
【讨论】:
等待子进程结束。至少赢了 这里的后台是在Windows“start”命令的帮助下实现的另一个操作系统...但它确实对我有用,谢谢! :-) 这在 win 10 上对我有用,但不会弹出 cli 窗口:start /B php wait.php args
【参考方案6】:
当然,对于windows
,您可以使用:
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("C:/path/to/php-win.exe -f C:/path/to/script.php", 0, false);
注意:
如果您收到COM
错误,请将扩展名添加到您的php.ini
并重新启动apache
:
[COM_DOT_NET]
extension=php_com_dotnet.dll
【讨论】:
我不知道,但它对我有用。请任何人解释 wscript.shell 是什么以及它的作用。 你能解释一下为什么这条线没有给出任何输出吗? ` $oExec = $WshShell->Run('C:\Users\Shreyash\Desktop\phantomjs-2.1.1-windows\bin\phantomjs.exe -f C:\xampp\htdocs\composer\test_0.js', 0 , 假);` test_0.js 可能有错误,检查幻像日志。【参考方案7】:如果它不在网页上,我建议生成某种信号(也许将文件放入目录中)并让 cron 作业接手需要完成的工作。否则,我们很可能会从 Apache 进程内部进入使用 pcntl_fork()
和 exec()
的领域,这很糟糕。
【讨论】:
你说这是一种糟糕的魔力。你能详细说明一下吗?【参考方案8】:这可行,但您必须小心不要使服务器过载,因为每次调用此函数时它都会创建一个新进程,该进程将在后台运行。如果同时只有一个并发调用,那么这个解决方法就可以了。
如果没有,那么我建议运行一个消息队列,例如 beanstalkd/gearman/amazon sqs。
【讨论】:
以上是关于有没有办法在不等待命令完成的情况下使用 shell_exec ?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用 time.Sleep 的情况下等待所有 goroutines 完成?
在不出现 Windows 控制台的情况下运行 Python 脚本
如何在不关闭 Executor 的情况下等待 ThreadPoolExecutor 中的所有任务完成?