PHP / pthreads Thread类不能使用数组?

时间:2013-02-10 10:15:37

标签: php multithreading pthreads

我发现PECL pthread Thread不能使用数组对象。我该怎么做才能找到原因?

代码示例:

   class my extends Thread {

           public function __construct() {
                   $this->arr = array();
                   $this->id  = 0;
           }
           public function run() {
                   while (true) {
                           $this->wait();
                   }
           }

           public function add() {
                   $this->id = rand(0, 1000);
                   $this->arr[] = rand(0, 1000);
                   var_dump($this->id);//this is rand
                   var_dump($this->arr);//this is empty array()
                   $this->notify();
           }
   }

   $my = new my();
   $my->start();
   while (true) {
           sleep(1);
           $my->add();
   } 

1 个答案:

答案 0 :(得分:35)

问题

PHP是一个无共享的环境:这意味着每个进程(或线程)必须拥有它自己的解释器副本,所有模块和用户代码。

HashTable结构不仅支持PHP数组,而且在整个PHP代码库中使用,从不打算被多个上下文操纵。

内存管理器,无论何时设置数组的新成员(相当于malloc),取消设置(相当于free)或更新一个(相当于free,然后malloc),都会被调用,是一个不可或缺的部分。无共享体系结构,除其他外,还专门用于禁止任何上下文释放由另一个上下文分配的内存,因为这构成了对共享内容的违反。

虚拟机假定它是操纵数组的唯一上下文。

所有扩展代码都采用相同的假设。

忽略规则的后果 - 什么都不分享 - 是可怕的:你崩溃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对象的自动不变性概念。

引用我的blog帖子关于pthreads v3中的不变性:

  

在pthreads v3中,将Threaded对象( A )的成员设置为另一个Threaded对象( B )会引用 A 保留 B 不可变。

不变性是一种性能优化。

显然,大多数数组的用例都涉及对数组进行变更,而Threaded个对象现在并不总是能够支持。

在这种特殊情况下,Threaded数组的所有成员都不是Threaded

pthreads v3(PHP7)引入了Volatile个对象的概念。

  

易变性形容词:容易变化迅速且不可预测,尤其是情况更糟。

Volatile个对象比Threaded个对象慢,因为它们无法从不变性允许我们进行的性能优化中受益。

Volatile个对象确实可以替代pthreads v3中的数组。当pthreads被设置为Volatile个对象的成员时,它们会将数组强制转换为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->arrayThread的运行时期间按预期运行。

有副作用,由以下代码的输出说明:

<?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操纵从另一个来源传入的数组时,自动强制可以降低每分钟的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一样,该阵列将被序列化以便存储。