问题
PHP是一个没有共享的环境:这意味着每个进程(或线程)必须具有它自己的解释器,所有模块和用户代码的副本.
不仅支持PHP数组,而且在整个PHP代码库中使用的HashTable结构从来没有被多个上下文操纵.
当你设置一个数组的新成员(相当于malloc)时,会调用这个内存管理器,而不是设置一个(相当于free)或更新一个(相当于free然后malloc)的内存管理器是共享的一个组成部分架构,其中尤其是专门设计为不允许任何上下文释放由另一个上下文分配的内存,因为这构成了对共享的任何内容的违反.
虚拟机假定它是操纵数组的唯一上下文.
所有扩展代码都做出相同的假设.
忽略规则的后果 – 不分享 – 是可怕的:你崩溃了PHP.
所有这一切使得您可以在多个上下文中存储和操作实际的数组,不可剥离,并且应该使它不受欢迎.
PHP5
将数组设置为Threaded对象的成员后,将其序列化.
您应该使用Threaded对象替换数组的使用.
Threaded对象可以像数组一样被操纵.
这里有一些让你开始的事情:
class Test extends Thread {
public function __construct(Threaded $storage) {
$this->storage = $storage;
}
public function run(){
$i = 0;
while(++$i < 10) {
$this->storage[]=rand(0,1000);
}
$this->synchronized(function($thread){
$thread->stored = true;
$thread->notify();
}, $this);
}
}
$storage = new Threaded();
$my = new Test($storage);
$my->start();
$my->synchronized(function(Thread $thread){
while (!$thread->stored) {
$thread->wait();
}
}, $my);
var_dump($storage);
?>
PHP7
pthreads v3(PHP7)介绍了Threaded对象的自动不变性的概念.
引用我的blog帖子不变性在pthreads v3:
In pthreads v3, setting a member of a Threaded object (A) to another Threaded object (B) makes the reference that A holds to B immutable.
不变性是性能优化.
显然,数组的大多数用例涉及到突变数组,哪些Threaded对象现在并不总是能够支持.
在这种特殊情况下,Threaded数组的所有成员都不是Threaded的.
pthreads v3(PHP7)引入了Volatile对象的概念.
Volatile, Adjective: Liable to change rapidly and unpredictably, especially for the worse.
易失性对象比Threaded对象慢,因为它们不能从不变性允许我们做出的性能优化中受益.
易失性对象可以很好地替代pthreads v3中的数组.当将它们设置为Threaded对象的成员时,pthreads会将数组强制转换为Volatile对象:
class Test extends Thread {
public function run(){
$array = [
"Hello",
"World"
];
var_dump($array);
$this->array = $array;
var_dump($this->array);
}
}
$test = new Test();
$test->start() && $test->join();
?>
会产生:
array(2) {
[0]=>
string(5) "Hello"
[1]=>
string(5) "World"
}
object(Volatile)#2 (2) {
[0]=>
string(5) "Hello"
[1]=>
string(5) "World"
}
这导致$this->数组在Thread的运行时期间按预期的方式运行.
有一个副作用,由以下代码的输出说明:
class Test extends Thread {
public function __construct(array $array) {
$this->array = $array;
}
public function run(){
var_dump($this->array);
}
}
$array = [
"Hello",
"World"
];
$test = new Test($array);
$test->start() && $test->join();
var_dump($array);
?>
会产生:
object(Volatile)#2 (2) {
[0]=>
string(5) "Hello"
[1]=>
string(5) "World"
}
array(2) {
[0]=>
string(5) "Hello"
[1]=>
string(5) "World"
}
请注意,线程中的Volatile对象与提供给其构造函数的数组断开连接,因此主上下文仍在操纵数组.
当线程操纵从另一个源传递的数组时,自动强制用于减少每分钟wtfs的速率.
总是更好地明确;不依赖强制是最好的选择.
如果您已经知道一些依赖关系将是数组,那么在将它们设置为成员之前,将其处理,从而完全避免强制.
可以通过使用显式转换来避免对Volatile的自动强制:
class Test extends Thread {
public function run() {
$this->result = (array) [
"Hello" => "World"
];
}
}
$test = new Test();
$test->start() && $test->join();
var_dump($test->result);
?>
会屈服
array(1) {
["Hello"]=>
string(5) "World"
}
如示例代码所示,当您真正想要使用数组来存储结果时,这很有用.与PHP5一样,数组将被序列化存储.