Я нашел 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(); }
PHP – это среда без общего доступа: это означает, что каждый процесс (или поток) должен иметь свою собственную копию интерпретатора, всех модулей и кода пользователя.
Структура HashTable
которая не только поддерживает массивы PHP, но используется во всей базе PHP-кода, никогда не предназначалась для управления несколькими контекстами.
Менеджер памяти, который будет вызываться всякий раз, когда вы устанавливаете новый член массива (эквивалент malloc), unset one (эквивалент бесплатного) или обновляете один (эквивалент free then malloc), является неотъемлемой частью общего ничего архитектура и, кроме всего прочего, специально предназначена для того, чтобы запретить любой контекст свободной памяти, который был выделен другим контекстом, поскольку это является нарушением общего ничего.
Виртуальная машина предполагает, что это единственный контекст, манипулирующий массивом.
Все добавочные коды делают одно и то же предположение.
Последствия для игнорирования правил – ничего не разделяйте – ужасны: вы разбиваете PHP.
Все это позволяет вам хранить и манипулировать фактическим массивом в нескольких контекстах нереализуемым, и сделать его нежелательным.
Массивы будут сериализованы после установки их в качестве элемента 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); ?>
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. pthreads будет принудительно использовать массивы для объектов Volatile
когда они будут установлены как элементы Threaded
objects:
<?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, массив будет сериализован для хранения.