简介
Pthreads 是 PHP 的多线程扩展,可以用于并行执行。目前兼容 PHP7,但不可用于 cgi 模式
安装
在使用 PHP7 较新的版本时,直接下载最新的 release 版本时,可能会遇到无法编译的问题。因此,直接从 GitHub 下载最新的源代码,再进行安装
git clone https://github.com/krakjoe/pthreads.git
cd pthreads
phpize
./configure
make
make install
需要注意的是,pthreads 需要线程安全(zts)版本的 PHP,很多时候我们的 PHP 并不是线程安全的版本(non-zts)这时候就需要重新编译 PHP,加上--enable-maintainer-zts参数
基本应用
通过实例化Thread类(及子类)可以新建一个线程。其中,需要包括一个名为run的函数,用于实际用途,通过Thread::start运行,例如:
<?php
class MyThread extends Thread {
public function __construct() {
}
public function run() {
sleep(rand(1,5));
echo 'test';
}
}
$thread = new MyThread;
$thread->start();
在子线程中执行的所有操作都是异步的。子线程之间变量不共享,且线程的执行顺序不定
例如:
<?php
$test = NULL;
class MyThread extends Thread {
public $i;
public function __construct($i) {
$this->i = $i;
}
public function run() {
global $test;
sleep(rand(1, 3));
echo 'test ',$this->i, "\n";
var_dump($test);
if ($test === NULL) {
$test = $this->i;
}
}
}
$thread_array = [];
for ($i = 0; $i <= 10; $i++) {
$thread_array[$i] = new MyThread($i);
$thread_array[$i]->start();
}
foreach ($thread_array as $k => $v) {
while($thread_array[$k]->isRunning()) {
usleep(50);
}
}
echo 'All task finished';
输出结果可能为(顺序不定):
test 2
NULL
test 7
NULL
test 9
NULL
test 10
NULL
test 1
NULL
test 4
NULL
test 5
NULL
test 0
NULL
test 3
NULL
test 6
NULL
test 8
NULL
All task finished
关于数组
从 PHP7 对数组引入了一个新的优化特性,在 Swoole 官方文档中可以看到:
PHP7+Swoole 开启 opcache,运行时出现 zend_mm_heap corrupted。这个问题的主要原因是 PHP7 增加了一个优化项,如果 PHP 代码中一个数组只声明一次,并且没有对数据进行修改操作。PHP7 会将此数组转为 immutable 类型,此数组仅作为只读。
PHP7 的解析器只能识别 PHP 程序中的数组操作行为,但是扩展层对数组的修改无法识别。而 Swoole 的 Server->set 等方法可能会修改传入的数组,导致出现内存错误。
在 Phtreads 中,扩展为了防止出现这种问题,会将数组转为Volatile对象。对于普通的数组读写不会有太多困扰,但是会导致in_array等函数报错,解决方法是加上一个强制类型转换:
var_dump(in_array($id, (array)$this->ids));
其他
-
在子线程中执行
exit等会直接中断的代码,并不会使所有线程停止,只会使当前线程停止 -
run中的代码执行完成后,线程会立刻退出 -
想了解更多可以移步官方文档
-
最后推荐一下 Swoole,是一个 PHP 的异步并行扩展,内置了很多实用功能,且支持多进程