Pthreads:PHP的多线程扩展

Pthreads:PHP的多线程扩展

简介

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的异步并行扩展,内置了很多实用功能,且支持多进程