如何在PHP应用程序中使用multithreading
有没有一种在PHP中实现multithreading模型的现实方式,无论是真的,还是只是模拟它。 一段时间以来,build议您可以强制操作系统加载PHP可执行文件的另一个实例,并处理其他同时进程。
这个问题是当PHP代码完成执行PHP实例时仍然保留在内存中,因为没有办法从PHP中杀死它。 所以如果你模拟了几个线程,你可以想象会发生什么事情。 所以我仍然在寻找一种可以在PHP中完成或模拟multithreading的方法。 有任何想法吗?
multithreading是可能的在PHP中
是的,你可以用pthreads在PHP中进行multithreading
从PHP文档 :
pthreads是一个面向对象的API,提供了PHP中multithreading所需的所有工具。 PHP应用程序可以创build,读取,写入,执行和同步线程,工作者和线程对象。
警告 :pthreads扩展名不能在Web服务器环境中使用。 因此,PHP中的线程只能保留在基于CLI的应用程序中。
简单的testing
#!/usr/bin/php <?php class AsyncOperation extends Thread { public function __construct($arg) { $this->arg = $arg; } public function run() { if ($this->arg) { $sleep = mt_rand(1, 10); printf('%s: %s -start -sleeps %d' . "\n", date("g:i:sa"), $this->arg, $sleep); sleep($sleep); printf('%s: %s -finish' . "\n", date("g:i:sa"), $this->arg); } } } // Create a array $stack = array(); //Initiate Multiple Thread foreach ( range("A", "D") as $i ) { $stack[] = new AsyncOperation($i); } // Start The Threads foreach ( $stack as $t ) { $t->start(); } ?>
首先运行
12:00:06pm: A -start -sleeps 5 12:00:06pm: B -start -sleeps 3 12:00:06pm: C -start -sleeps 10 12:00:06pm: D -start -sleeps 2 12:00:08pm: D -finish 12:00:09pm: B -finish 12:00:11pm: A -finish 12:00:16pm: C -finish
第二次运行
12:01:36pm: A -start -sleeps 6 12:01:36pm: B -start -sleeps 1 12:01:36pm: C -start -sleeps 2 12:01:36pm: D -start -sleeps 1 12:01:37pm: B -finish 12:01:37pm: D -finish 12:01:38pm: C -finish 12:01:42pm: A -finish
真实世界的例子
error_reporting(E_ALL); class AsyncWebRequest extends Thread { public $url; public $data; public function __construct($url) { $this->url = $url; } public function run() { if (($url = $this->url)) { /* * If a large amount of data is being requested, you might want to * fsockopen and read using usleep in between reads */ $this->data = file_get_contents($url); } else printf("Thread #%lu was not provided a URL\n", $this->getThreadId()); } } $t = microtime(true); $g = new AsyncWebRequest(sprintf("http://www.google.com/?q=%s", rand() * 10)); /* starting synchronization */ if ($g->start()) { printf("Request took %f seconds to start ", microtime(true) - $t); while ( $g->isRunning() ) { echo "."; usleep(100); } if ($g->join()) { printf(" and %f seconds to finish receiving %d bytes\n", microtime(true) - $t, strlen($g->data)); } else printf(" and %f seconds to finish, request failed\n", microtime(true) - $t); }
你为什么不用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]); } }
线程在股票PHP中不可用,但通过使用HTTP请求作为asynchronous调用可以进行并发编程。
将curl的超时设置设置为1,并将相同的session_id用于要相互关联的进程,可以使用会话variables进行通信,如下面的示例中所示。 有了这个方法,你甚至可以closures你的浏览器,并发进程仍然存在于服务器上。
不要忘记像这样validation正确的会话ID:
http://localhost/test/verifysession.php?sessionid = [正确的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中。 在这里有用的两个函数集是:
过程控制functionhttp://www.php.net/manual/en/ref.pcntl.php
POSIX函数http://www.php.net/manual/en/ref.posix.php
你可以用pcntl_fork分叉你的进程 – 返回孩子的PID。 然后你可以使用posix_kill来去除那个PID。
也就是说,如果你杀了一个父进程,一个信号应该发送给subprocess,告诉它死。 如果php本身不能识别这个,你可以注册一个函数来pipe理它,并使用pcntl_signal做一个干净的退出。
使用线程可以通过pthread PECL扩展
我知道这是一个古老的问题,但对于search的人来说,有一个用C语言编写的PECL扩展,现在赋予PHPmultithreadingfunction,它位于https://github.com/krakjoe/pthreads
你可以模拟线程。 PHP可以通过popen(或proc_open)运行后台进程。 这些进程可以通过标准input和标准输出进行通信。 当然,这些过程本身可以是一个PHP程序。 这可能就像你会得到的一样。
你可以使用exec()来运行一个命令行脚本(比如命令行php),并且如果你将输出传送给一个文件,那么你的脚本不会等待命令完成。
我不记得PHP的CLI语法,但你会想要的东西,如:
exec("/path/to/php -f '/path/to/file.php' | '/path/to/output.txt'");
我认为不less共享主机服务器出于安全原因默认禁用exec(),但可能值得一试。
根据你想要做什么,你也可以使用curl_multi来实现它。
我知道这是古老的,但你可以看看http://phpthreadlib.sourceforge.net/
它支持双向的线程间通信,并且还具有内置的保护function,用于消除子线程(防止孤儿)。
您可以select:
- multi_curl
- 可以使用相同的系统命令
- 理想的情况是,用C语言创build一个线程函数,并在PHP中进行编译/configuration。 现在这个函数将是PHP的函数。
pcntl_fork怎么样?
检查我们的手册页面的例子: PHP pcntl_fork
如果打开安全模式, pcntl_fork
将无法在Web服务器环境中工作。 在这种情况下,它只能在CLI的CLI版本中工作。
Thread类是可用的,因为PECL pthreads≥2.0.0。
可能是我错过了一些东西,但是exec在windows环境下对我来说并不是asynchronous的,我在windows中使用了它,并且像魅力一样工作;)
$script_exec = "c:/php/php.exe c:/path/my_ascyn_script.php"; pclose(popen("start /B ". $script_exec, "r"));
multithreading意味着同时执行多个任务或进程,我们可以通过使用下面的代码在php中实现,尽pipe在php中没有直接的方法来实现multithreading,但是我们可以通过以下方法获得几乎相同的结果。
chdir(dirname(__FILE__)); //if you want to run this file as cron job for ($i = 0; $i < 2; $i += 1){ exec("php test_1.php $i > test.txt &"); //this will execute test_1.php and will leave this process executing in the background and will go //to next iteration of the loop immediately without waiting the completion of the script in the //test_1.php , $i is passed as argument .
}
Test_1.php
$conn=mysql_connect($host,$user,$pass); $db=mysql_select_db($db); $i = $argv[1]; //this is the argument passed from index.php file for($j = 0;$j<5000; $j ++) { mysql_query("insert into test set id='$i', comment='test', datetime=NOW() "); }
这将同时执行两次test_1.php,两个进程将同时在后台运行,这样就可以在php中实现multithreading了。
这个人做了很好的工作在PHPmultithreading