210

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

我研究了各种exec(), shell_exec(),pcntl_fork()等功能,但似乎没有一个能提供我想要的东西。(或者,如果他们这样做,我不清楚怎么做。)有什么建议吗?

4

13 回答 13

234

如果它“不关心输出”,难道不能用&后台进程调用脚本的 exec 吗?

编辑- 结合@AdamTheHut对此帖子的评论,您可以将其添加到以下调用中exec

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

这会将stdio(first >) 和stderr( 2>) 重定向到/dev/null后台并在后台运行。

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


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

" &> /dev/null &"
于 2008-10-21T16:08:03.283 回答
57

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

<?php
    `echo "the command"|at now`;
?>
于 2008-10-21T22:20:47.040 回答
39

致所有 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

于 2016-10-25T15:12:07.660 回答
23

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

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

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

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

于 2008-10-21T22:27:26.450 回答
13

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

于 2008-10-21T22:29:26.537 回答
6

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

mycommand -someparam somevalue &

在 Windows 中,您可以使用“开始”DOS 命令

start mycommand -someparam somevalue
于 2008-10-21T22:46:46.720 回答
6

正确的方法(!)做到这一点是

  1. 叉()
  2. 设置ID()
  3. 执行()

fork 分叉,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();
于 2008-11-14T15:31:56.447 回答
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 &");
}

(在哪里PHP_PATH定义类似define('PHP_PATH', '/opt/bin/php5')或类似的 const)

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

于 2010-07-19T20:25:46.317 回答
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

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

于 2017-10-10T22:45:58.693 回答
4

我发现真正对我有用的唯一方法是:

shell_exec('./myscript.php | at now & disown')
于 2012-02-08T18:11:32.177 回答
2

您还可以将 PHP 脚本作为daemoncronjob运行:#!/usr/bin/php -q

于 2008-11-07T07:33:53.567 回答
1

使用命名的 fifo。

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

然后,每当您想启动长时间运行的任务时,只需编写一个换行符(非阻塞到触发器文件。

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

于 2008-11-14T15:47:02.207 回答
1

不使用队列,你可以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);
于 2016-12-21T10:18:55.900 回答