Подтвердить что ты не робот

Класс PHP/pthreads Thread не может использовать массив?

Я нашел PECL pthread Thread не может использовать объект массива. Что я могу сделать, чтобы найти причину?

Пример кода:

   class my extends Thread {

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

           public function set() {
                   $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();
   } 
4b9b3361

Ответ 1

Проблема

PHP - это среда без общих соединений: это означает, что каждый процесс (или поток) должен иметь свою собственную копию интерпретатора, всех модулей и кода пользователя.

Структура HashTable, которая не только поддерживает массивы PHP, но используется на всей базе PHP-кода, никогда не предназначалась для управления несколькими контекстами.

Менеджер памяти, который будет вызываться всякий раз, когда вы устанавливаете новый элемент массива (эквивалент malloc), unset one (эквивалент free) или обновляете один (эквивалент free then malloc), является неотъемлемой частью архитектура общего ничего, и, кроме всего прочего, специально предназначена для того, чтобы запретить любой контекст свободной памяти, который был выделен другим контекстом, поскольку это представляет собой нарушение общего ничего.

Виртуальная машина предполагает, что это единственный контекст, управляющий массивом.

Весь код расширения делает то же самое допущение.

Последствия для игнорирования правил - ничего не сообщайте - ужасны: вы разбиваете PHP.

Все это позволяет вам хранить и манипулировать фактическим массивом в нескольких контекстах нереалистично и делать это нежелательно.

PHP5

Массивы будут сериализованы после установки их как члена объекта Threaded.

Вы должны заменить использование массивов объектами Threaded.

Объект A 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->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.

Автоматическое принуждение служит для уменьшения скорости wtfs-per-minute, когда Thread управляет массивом, который был передан из другого источника.

Всегда лучше быть явным; Не полагаться на принуждение - лучший вариант.

Если вы уже знаете, что некоторые зависимости будут массивами, тогда с этим справитесь, прежде чем устанавливать их как члены, полностью избегая принуждения.

Можно избежать автоматического принуждения до 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, массив будет сериализован для хранения.