问题
PHP 是一个无共享的环境:这意味着每个进程(或线程)必须拥有自己的解释器副本、所有模块和用户代码。
该HashTable
结构不仅支持 PHP 数组,而且在整个 PHP 代码库中都使用,从未打算由多个上下文操作。
每当您设置数组的新成员(相当于 malloc)、未设置一个成员(相当于 free)或更新一个成员(相当于 free 然后 malloc)时,都会调用内存管理器,它是 shared nothing 的组成部分架构,除其他外,专门设计为禁止任何上下文释放由另一个上下文分配的内存,因为这构成了对无共享的违反。
虚拟机假定它是唯一操作数组的上下文。
所有扩展代码都做出相同的假设。
忽略规则的后果——什么都不分享——是可怕的:你让 PHP 崩溃了。
所有这些都使您无法在多个上下文中存储和操作实际数组,并且无论如何都应该使它变得不受欢迎。
PHP5
数组将在将它们设置为Threaded
对象的成员时被序列化。
您应该用Threaded
对象替换数组的使用。
可以Threaded
像操作数组一样操作对象。
这里有一些让你开始的东西:
<?php
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
对象自动不变性的概念。
引用我关于 pthreads v3 中不变性的博客文章:
在 pthreads v3 中,将一个Threaded
对象 ( A ) 的成员设置为另一个Threaded
对象 ( B ) 会使A对B持有的引用不可变。
不变性是一种性能优化。
显然,数组的大多数用例都涉及改变数组,而Threaded
对象现在并不总是能够支持。
Threaded
在这种特殊情况下,数组的所有成员都不是Threaded
.
pthreads v3 (PHP7) 引入了Volatile
对象的概念。
易变的,形容词:容易迅速和不可预测地变化,尤其是变得更糟。
Volatile
对象比Threaded
对象慢,因为它们无法从不变性允许我们进行的性能优化中受益。
Volatile
在 pthreads v3 中,对象确实可以很好地替代数组。Volatile
当将数组设置为对象的成员时,pthread 会将数组强制转换为Threaded
对象:
<?php
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->array
在Thread
.
有一个副作用,如下代码的输出所示:
<?php
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
对象与提供给其构造函数的对象Thread
断开连接array
,因此主上下文仍在操作array
.
Thread
当 a操作从另一个源传入的数组时,自动强制用于降低每分钟 wtfs 的速率。
明确一点总是更好;不依赖强制是最好的选择。
如果您已经知道某些依赖项将是数组,那么在将它们设置为成员之前处理它,完全避免强制。
Volatile
通过使用显式强制转换可以避免自动强制转换:
<?php
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 一样,数组将被序列化以进行存储。