如何在PHP应用程序中使用多线程

时间:2020-03-05 18:55:33  来源:igfitidea点击:

是否存在一种实际的方式来实现PHP中的多线程模型,无论是真正的还是只是模拟它。一段时间以前,建议我们可以强制操作系统加载PHP可执行文件的另一个实例并处理其他同时进行的进程。

这样做的问题是,当PHP代码完成执行PHP实例后,它仍保留在内存中,因为无法从PHP中杀死它。因此,如果我们正在模拟多个线程,则可以想象会发生什么。因此,我仍在寻找一种可以在PHP中有效完成或者模拟多线程的方法。有任何想法吗?

解决方案

回答

虽然我们无法线程化,但是我们确实在php中具有一定程度的过程控制。这里有用的两个功能集是:

过程控制功能
http://www.php.net/manual/zh/ref.pcntl.php

POSIX功能
http://www.php.net/manual/zh/ref.posix.php

我们可以使用pcntl_fork返回我们孩子的PID来分叉进程。然后,我们可以使用posix_kill丢弃该PID。

就是说,如果我们杀死了一个父进程,则应该向子进程发送一个信号,告诉它死亡。如果php本身无法识别,则可以注册一个函数来对其进行管理,并使用pcntl_signal进行干净退出。

回答

我们可以使用exec()运行命令行脚本(例如命令行php),如果将输出通过管道传输到文件,则脚本将不等待命令完成。

我不太记得php CLI语法,但是我们想要这样的东西:

exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");

我认为出于安全原因,很多共享托管服务器默认情况下都禁用了exec(),但值得一试。

回答

库存的PHP中没有线程,但可以通过将HTTP请求用作异步调用来进行并发编程。

将curl的超时设置设置为1,并对要彼此关联的进程使用相同的session_id,则可以与会话变量进行通信,如下面的示例所示。使用这种方法,我们甚至可以关闭浏览器,并发进程仍在服务器上。

不要忘记像这样验证正确的会话ID:

http://localhost/test/verifysession.php?sessionid=[the correct id]

startprocess.php

$request = "http://localhost/test/process1.php?sessionid=".$_REQUEST["PHPSESSID"];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
echo $_REQUEST["PHPSESSID"];

process1.php

set_time_limit(0);

if ($_REQUEST["sessionid"])
   session_id($_REQUEST["sessionid"]);

function checkclose()
{
   global $_SESSION;
   if ($_SESSION["closesession"])
   {
       unset($_SESSION["closesession"]);
       die();
   }
}

while(!$close)
{
   session_start();
   $_SESSION["test"] = rand();
   checkclose();
   session_write_close();
   sleep(5);
}

verifysession.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
var_dump($_SESSION);

closeprocess.php

if ($_REQUEST["sessionid"])
    session_id($_REQUEST["sessionid"]);

session_start();
$_SESSION["closesession"] = true;
var_dump($_SESSION);

回答

我们可以模拟线程。 PHP可以通过popen(或者proc_open)运行后台进程。可以通过stdin和stdout与这些进程进行通信。当然,这些进程本身可以是php程序。那可能与我们将获得的接近。

回答

为什么不使用popen?

for ($i=0; $i<10; $i++) {
    // open ten processes
    for ($j=0; $j<10; $j++) {
        $pipe[$j] = popen('script2.php', 'w');
    }

    // wait for them to finish
    for ($j=0; $j<10; ++$j) {
        pclose($pipe[$j]);
    }
}