在PHP中创建新线程?

5
我有一个PHP脚本需要处理一些较长时间的任务。但是我不想让浏览者等待脚本完成,而是希望他可以继续浏览和/或关闭浏览器。然而,我希望这个脚本能够继续工作...如何实现呢?是否有一种方法可以创建某种类型的线程来实现这样的功能?
附言:我真的不想用另一种语言重写脚本并通过操作系统执行它。
5个回答

10
如果您可以从CLI运行脚本,那么您可以通过调用以下命令之类的命令,将其“分叉”到来自您的Web服务器提供服务的脚本的后台进程中:
如果你可以在CLI下运行你的脚本,你可以通过在你的web服务器提供的脚本中调用类似如下命令的方式来将它“fork”成一个后台进程:
exec('php your_script.php > /dev/null &');

这将允许页面完成加载,但保持your_script.php的运行。


我能否使用 $_GET 方式通过你的方式向我的脚本发送数据?一个示例是:exec('php my_script.php?somevalues > /dev/null &')。 - JohnRoach
1
@JohnRoach exec会在操作系统中运行一个命令。因此,您必须以这种方式传递参数,这里没有涉及HTTP(GET、POST等是HTTP方法)。PHP:命令行用法 - kapa

7
避免在PHP中运行并行任务(线程或进程)的想法。虽然它有一些模块可以用于此目的,但它们不适用于每个平台,并且不是PHP核心的一部分,因此您能够使用它们的机会非常低。
在这里您有两个选择:
1.将长时间运行的任务拆分为几个更便宜的子任务。将它们放在队列中,使每个请求执行其中的一些子任务(但不要延迟向客户端的输出太多)。
2.如果无法将此大型任务拆分,只需为其设置cron作业。这样,用户不会受到延迟的影响,因为系统执行长时间运行的任务。
另外需要注意的一点是,PHP脚本具有(可覆盖的)时间限制,在给定的秒数之后停止执行。通过cron运行的任务不会受到此限制的影响。

2
据我所知,PHP没有提供任何执行此类任务的功能。
一个可行(虽然不太好看)的解决方案是创建SOAP Web服务,并使用扩展的SoapClient从脚本中调用它,通过覆盖"$oneWay"参数来实现(参见http://www.php.net/manual/en/soapclient.dorequest.php)。
    class AsyncSoapClient extends SoapClient {
      function __construct($wsdl, $options) {
        parent::__construct($wsdl, $options);
      }

      function __doRequest($request, $location, $action, $version, $oneWay = TRUE) {
        return parent::__doRequest($request, $location, $action, $version, TRUE);
      }
    }

    $client = new AsyncSoapClient(
      NULL,
      array(
        'location' => $location,
        'uri'      => $uri
      )
    );

    $client->invokeMethodOnServer($yourParameters);

在这种情况下,单向请求意味着您的脚本不需要等待响应,代码的执行将继续。

你说这是丑陋的方式,为什么呢?看起来你的解决方案恰好就是我想要的。 - JohnRoach
更自然的做法是使用事件池或不同的线程来实现这样的目的。虽然这个解决方案可行,但你需要创建一个接受客户端请求的SOAP服务器,实现单向SOAP客户端等... - ioseb

1
你可以利用ajax,通过ajax调用需要长时间执行的脚本,当结果准备好时,将其显示给用户。

1
用户可以导航到不同的页面或关闭浏览器,那么脚本执行将被中断/丢失。 - Remus Rusanu
正是因为这个原因,我才在stackoverflow上发布了我的问题... - JohnRoach
@VladislavZorov:因为AJAX(JS)在客户端运行。用户可能会中断调用(或完全禁用JS),如果操作时间较长,请求可能会超时等等。而且,问题不是关于AJAX,而是关于能否在后台运行PHP操作。这两者不应混淆。 - kraxor
1
那是过去的我,忽略那个人。 - Vladislav Zorov
1
PHP不一定只用于网站。例如,我正在使用PHP构建一个Telegram机器人,因此您的答案不能适用于此目的。 - Marco Concas

1

如果可以的话,您可以做另一件事情,即维护一个表格来记录脚本执行的状态, 然后编写一个JavaScript代码,进行ajax调用以检查记录的状态,如果为真,则检索数据,然后向用户显示它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接