Сделать сценарий сбой путем сериализации Closure
Используя потоки PHP, я несколько раз сталкивался с фатальной ошибкой "Сериализация замыкания". Однако я не понимаю, как это происходит: я не передаю закрытие или любой вызываемый объект другому потоку, иногда, когда я беру код за пределами проекта и запускаю его один, он работает, но не получается в проекте.
Поэтому я попытался заставить скрипт потерпеть неудачу путем сериализации закрытия, чтобы понять, как он на самом деле работает.
Этот код использует замыкания и фактически работает:
<?php
class MyWorker extends Worker {
protected $kernel;
protected $container;
public function __construct($closure)
{
echo "Worker::__construct()";
echo PHP_EOL;
echo $closure();
echo PHP_EOL;
}
public function run()
{
echo "Worker::run()";
echo PHP_EOL;
}
}
class Toto {
protected $c;
public function __construct()
{
$this->c = function() {
return "CLOSURE";
};
}
public function go()
{
$c = $this->c;
$pool = new Pool(4, MyWorker::class, [function(){
return "WORKER_CLOSURE";
}]);
$pool->submit(new class ($c) extends Threaded {
public function __construct($c)
{
$this->c = $c;
}
public function run()
{
$c = $this->c;
echo $c();
echo "Threaded::run()";
echo PHP_EOL;
}
});
}
}
$toto = new Toto;
$toto->go();
Когда бегаю один. Но внутри команды Symfony следующий код просто не работает. Я не понимаю почему, поэтому я не могу это исправить:
<?php
use Threaded;
use Thread;
class Foo
{
public function run()
{
$t = new Thread;
$t->start();
$t->join();
}
}
Так что я подумал, может быть, это потому, что этот код выполняется в закрытии (я не знаю, но, может быть), поэтому я попробовал это:
$c = function() {
$t = new class extends Thread {
public function run()
{
echo "yo";
}
};
$t->start();
$t->join();
};
$c();
И это работает. Так что передача замыкания в поток работает, построение, запуск и присоединение потока изнутри замыкания также работает, я не знаю, где искать сейчас...
Я тоже смотрю на это: не удается сохранить замыкания в потоке, но код устарел, и теперь он работает ( PHP 7, pthreads 3.x). Поэтому здесь я прошу помощи, чтобы понять, что на самом деле проблема с закрытием...
1 ответ
Последние версии pthreads
разрешить сериализацию Closure
объекты; При использовании в качестве члена свойства Threaded
объект, pthreads
создает копию функции, которую Closure
закрывается для выполнения в других контекстах.
Zend до сих пор не разрешает сериализацию Closure
объекты:
class Member {
public function __construct(Closure $closure) {
$this->closure = $closure;
}
public $closure;
}
class Fail extends Thread {
public function __construct(Member $member) {
$this->member = $member;
}
public function run() {
($this->member->closure)();
}
private $member;
}
$member = new Member(function(){
echo "can only work if Member is Threaded !\n";
});
$fail = new Fail($member);
$fail->start() && $fail->join();
Код выше не будет работать как есть, потому что Member
сериализуется, когда устанавливается в качестве члена Threaded
объект, это приводит к pthreads
пытаясь сериализовать Closure
,
Объявление участника таким образом:
class Member extends Threaded
Заставит это вести себя как ожидалось.
Я не достаточно знаком с Symfony, чтобы сказать вам, где искать решение проблемы, но это, безусловно, причина этого; Closure
был установлен как свойство члена объекта, который pthreads
впоследствии пытается сериализовать.