提到php多线程,网上的例子基本都是并发发起http请求,难道php多线程就只能干这个吗,搞笑。
于是,我写了一个使用多线程对100万个数的排序,在测试的过程中发现了几个问题,记录一下。
php多线程只有在实例化的时候有机会传入参数,于是,当我传入数组的时候,发现有点不对劲。
class Test extends Thread{
public $data;
public $response;
public function __construct($fruit){
var_dump($fruit);
$this->data = $fruit;
var_dump($this->data);
}
public function run(){
}
}
$fruit = ['apple', 'balana', 'orange'];
$p = new Test($fruit);
$p->start();
var_dump($p); // 为了查看线程是否还在,如果线程内有错误的话,线程就会被 destroy
结果:
array(3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
object(Volatile)#2 (3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
object(Test)#1 (2) {
["data"]=>
object(Volatile)#2 (3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
["response"]=>
NULL
}
也就是说,在构造函数中,我传入数组,给属性赋值的时候,就变成了 Volatile 对象。
关于 Volatile 对象,查看官方文档:https://php.net/manual/en/class.volatile.php
2、修改run()方法
public function run(){
$this->response = $this->data;
}
结果:报错
也就说,只有构造函数中初始化的属性才配用上 Volatile 对象 。。。。。。
3、修改run()方法
public function run(){
$this->data= null;
}
结果:报错
PHP Fatal error: Uncaught RuntimeException: Threaded members previously set
to Threaded objects are immutable, cannot overwrite data
也就说,构造函数中初始化的属性还不能改动它。。。。。。。。。
4、修改run()方法
public function run(){
$this->response = (array)$this->data;
var_dump($this->response);
}
结果:可行
array(3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
object(Test)#1 (2) {
["data"]=>
object(Volatile)#2 (3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
["response"]=>
array(3) {
[0]=>
string(5) "apple"
[1]=>
string(6) "balana"
[2]=>
string(6) "orange"
}
}
对于 Volatile 对象 ,懒得去研究,直接转数组就可以操作了啊。
5、修改run()方法
public function run(){
$data = (array)$this->data;
$data[5] = 55;
$this->response = $data;
}
结果:报错,线程已终止
这就很无语了,莫名其妙嘛,于是尝试这
t
h
i
s
−
>
r
e
s
p
o
n
s
e
=
(
a
r
r
a
y
)
this->response = (array)
this−>response=(array)data;
尼玛,这样可以,呵呵,没搞懂。
注意点:
1.线程类的属性不能直接进行哈希表(数组)操作,如:
//这样是无效的
$this->var1["hello"] = "world";
//改为
$this->var1 = ["hello"=>"world"];
因为线程类属性的赋值是通过序列化实现的,其本质是存储了序列化数据,因此不支持PHP常用直接操作哈希表(数组)的操作
2.线程类的属性不能是“闭包函数”
原因:闭包函数不能序列化;因此,如果想在线程里用“回调函数”的话,那就放弃线程吧;
3.线程对象开辟了php的第二空间
线程在创建之后,无法访问到父线程的变量,诸如$GLOBALS或global等用法都无法操作父线程的全局变量,这应该是考虑到了线程安全的问题;
但是父线程却能够访问子线程对象的内容;
4、传递数据库实例到线程里是无效的
传递进来的对象是好的,就是却无法执行数据库操作。建议还是在线程里去实例化数据库连接吧。