如何在不阻塞线程的情况下调用PHP?

时间:2012-07-02 18:40:20

标签: php

我有2个PHP文件。一个文件是caller.php,另一个是worker.php

caller.php将在(linux)系统上启动worker.php并且caller.php应该立即结束(而worker.php仍然在服务器上运行)

worker.php占用了大量时间,它会将状态写入数据库或文件。

我希望能够在启动'php worker.php'的浏览器中打开caller.php,关闭浏览器,在5分钟后返回并检查状态..(或者脚本将在完成后发送邮件) - 任何想法如何做到这一点?

3 个答案:

答案 0 :(得分:2)

您可以结束客户端连接并继续处理,全部完成。如果处理比php / httpd全局配置允许的时间更长,您可能还想增加php超时。请参阅set_time_limit();

这不是你提出的问题,但我认为这可能是X / Y问题所以我们在这里使用的技术可以用来:

  • 向用户显示处理已开始页面。
  • 关闭用户连接。
  • 开始更长时间的处理。

所以基本上这可以回答你描述的需求,而不是“如何做X?”。

呼叫者

// Ignore user abort and set Connection close header
ignore_user_abort(true);
header("Connection: close");

// Start controlled buffering
ob_start();
echo "<h1>Processing started, come back tomorrow to see results</h1>";

// Get buffer length and manually add it to headers.
$size = ob_get_length();
header("Content-Length: $size");

// Flush buffers, user sees "Processing started" message.
ob_end_flush();
flush();

// At this point connection to client should be closed already.
// Here we start our worker, there is no need to do fork() or 
// anything like that. Client browser is not listening anymore.
// All we need to do is simply start working and start writing
// status logs to somewhere so that client can retrieve status
// with another request, let's say from checkworkerstatus.php
include "worker.php";
$worker = new worker();
$worker->start_long_processing();

不分支或查杀callerworker单独运行?

这是对的,那是因为没有必要。

是的,你问过“caller.php会在(linux)系统上启动worker.php的行为,而caller.php应该立即结束(而worker.php仍在服务器上运行)”< / i>的。但是,如果您不想multithreading-singleuser app with php,则无需这样做。只需让用户 1。启动一些东西, 2。让它继续运行, 3。断开用户连接, 4。 go回到开始,用户可以开始更多的东西,或者如果已经足够无聊就退出。

当然你可以用flush();之后的任何内容替换所有内容,不同之处在于客户端不再监听,以便所有输出都转到名为/ dev / null的黑洞。例如,用这样的东西测试它:

...end_flush();
flush();

// At this point connection to client should be closed already.
echo "Nobody sees this message";
while(rand(0,10) != 1) {
    echo "Nobody sees this message";
    error_log(date("mdyHis")." Still running...");
    sleep(10);
}
...

有关详细信息,请参阅http://php.net/features.connection-handling 如果刷新缓冲区和关闭用户连接似乎有任何问题,也请阅读http://php.net/function.flush 关于Why does PHP not support multithreading?

还有另一个问题(有答案)

答案 1 :(得分:1)

  1. 来电者运行工人
  2. Worker在/ tmp /中创建FIFO文件并向其写入有关进度的信息(您也可以使用套接字)
  3. 来电者读取此档案并显示用户实际进度
  4. 如果您将配置Apache / nginx,它将允许同时执行两个PHP文件(就像我的一样)。

    您应该阅读posix_mkfifo:http://php.net/manual/en/function.posix-mkfifo.php(也有使用示例)。

答案 2 :(得分:1)

这可能有点强,但是最快捷直接的方式:

  • 来电者使用&lt; IFRAME&gt;
  • 创建一个html
  • IFRAME的SRC是工作人员(这里调用者传递给工作人员作为GET-params)
  • 第一行工人在下面的代码中

代码:

ignore_user_abort(true);
set_time_limit(0);

当你关闭浏览器工作者(应该)计数工作时!

请参阅http://www.php.net/manual/en/function.ignore-user-abort.php