如何在PHP应用程序中使用多线程
是否存在一种实际的方式来实现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]); } }