提问人:AdamTheHutt 提问时间:10/22/2008 最后编辑:BoazAdamTheHutt 更新时间:9/13/2022 访问量:191286
PHP 中的异步 shell exec
Asynchronous shell exec in PHP
问:
我有一个PHP脚本,它需要调用shell脚本,但根本不关心输出。shell 脚本会进行许多 SOAP 调用,并且完成速度很慢,因此我不想在等待回复时减慢 PHP 请求的速度。事实上,PHP 请求应该能够在不终止 shell 进程的情况下退出。
我研究了各种 、 、 等函数,但它们似乎都没有提供我想要的。(或者,如果他们这样做了,我不清楚是怎么回事。有什么建议吗?exec()
shell_exec()
pcntl_fork()
答:
如果它“不关心输出”,那么脚本的 exec 是否不能在后台调用进程?&
编辑 - 结合@AdamTheHut对这篇文章的评论,您可以将其添加到以下调用中:exec
" > /dev/null 2>/dev/null &"
这会将 (first ) 和 () 重定向到后台并在后台运行。stdio
>
stderr
2>
/dev/null
还有其他方法可以做同样的事情,但这是最简单的阅读方法。
上述双重重定向的替代方法:
" &> /dev/null &"
评论
&> /dev/null &
/dev/null
/dev/null
我用过 at,因为它确实启动了一个独立的过程。
<?php
`echo "the command"|at now`;
?>
评论
www-data
at
<?php exec('sudo sh -c "echo \"command\" | at now" ');
command
echo "sudo command" | at now
www-data
/etc/at.deny
at
对于某些 Linux 发行版,package (和 command) 不是默认的。此外,它需要运行服务。由于缺乏解释,此解决方案可能难以理解。atd
在 linux 上,您可以执行以下操作:
$cmd = 'nohup nice -n 10 php -f php/file.php > log/file.log & printf "%u" $!';
$pid = shell_exec($cmd);
这将在命令提示符下执行命令,然后只返回 PID,您可以检查 > 0 以确保它正常工作。
这个问题是类似的:PHP有线程吗?
评论
action=generate var1_id=23 var2_id=35 gen_id=535
$cmd = 'nohup nice -n 10 /path/to/script.sh > /path/to/log/file.log & printf "%u" $!';
nice
ionice
&
printf
$!
php-execute-a-background-process 有一些很好的建议。我认为我的很好,但我有偏见:)
在 Linux 中,您可以通过在命令末尾附加一个 & 符号,在新的独立线程中启动进程
mycommand -someparam somevalue &
在 Windows 中,您可以使用“start”DOS 命令
start mycommand -someparam somevalue
评论
start
/B
您也可以将 PHP 脚本作为守护程序或 cronjob 运行:#!/usr/bin/php -q
正确的方法是
- fork()
- 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();
评论
使用命名的 fifo。
#!/bin/sh
mkfifo trigger
while true; do
read < trigger
long_running_task
done
然后,每当您想启动长时间运行的任务时,只需在触发器文件中写入换行符(非阻塞)。
只要您的输入小于并且是单个操作,您就可以将参数写入 fifo 并让它们显示在脚本中。PIPE_BUF
write()
$REPLY
我用了这个...
/**
* 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 &");
}
(其中 const 定义相似或相似)PHP_PATH
define('PHP_PATH', '/opt/bin/php5')
它通过命令行传入参数。要在 PHP 中读取它们,请参阅 argv。
我发现真正对我有用的唯一方法是:
shell_exec('./myscript.php | at now & disown')
评论
shell_exec("/usr/local/sbin/command.sh 2>&1 >/dev/null | at now & disown")
sh: 1: disown: not found
致所有 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
评论
myscript.js
node myscript.js
php artisan
如果没有 use queue,您可以像这样使用 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);
我还发现 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 存储库中查看它的工作原理。
评论
proc_*
我不能在 Windows 上使用,所以我改用。我在 Windows 7.4.23 上运行 PHP 11。 > /dev/null 2>/dev/null &
proc_open
这是我的代码。
function run_php_async($value, $is_windows)
{
if($is_windows)
{
$command = 'php -q '.$value." ";
echo 'COMMAND '.$command."\r\n";
proc_open($command, [], $pipe);
}
else
{
$command = 'php -q '.$value." > /dev/null 2>/dev/null &";
echo 'COMMAND '.$command."\r\n";
shell_exec($command);
}
}
$tasks = array();
$tasks[] = 'f1.php';
$tasks[] = 'f2.php';
$tasks[] = 'f3.php';
$tasks[] = 'f4.php';
$tasks[] = 'f5.php';
$tasks[] = 'f6.php';
$is_windows = true;
foreach($tasks as $key=>$value)
{
run_php_async($value, $is_windows);
echo 'STARTED AT '.date('H:i:s')."\r\n";
}
在每个要执行的文件中,我都把 delay 这个:
<?php
sleep(mt_rand(1, 10));
file_put_contents(__FILE__.".txt", time());
所有文件都是异步执行的。
评论
nice
ionice
/usr/bin/ionice -c3 /usr/bin/nice -n19
)