Autor Zpráva
David Klouček
Profil
Třída Program využívá Model, který potřebuje připojení k databázi. Teď potřebuju Program spustit ve více vláknech najednou. Zkouším to pomocí rozšíření pthreads. Když spustím následující kód:

<?php
$connection = new PDO('mysql:host=localhost;dbname=x', 'y', 'z');

class Model {
    public $connection;
    public function setConnection(PDO $connection) {
        $this->connection = $connection;
        //echo get_class($this->connection)." | setConnection<br />\n"; //zde ještě vrátí PDO
    }
}

class Program {
    public $model;
    public function setModel(Model $model) {
        $this->model = $model;
    }
    public function run() {
        echo get_class($this->model->connection)." | run<br />\n";
    }
}

class ProgramThread extends Thread {
    public $i;
    public $program;

    public function __construct($i, Program $program, PDO $connection)
    {
        $this->i = $i;
        $this->program = $program;
        $this->program->model->setConnection($connection);
        echo get_class($this->program->model->connection)." | __construct<br />\n";
    } 

    public function run()
    {
        $this->program->run();
    }
}

$program = new Program();
$model = new Model;//nemůžu předat připojení už teď do modelu, hlásilo by to nelze serializovat PDO
$program->setModel($model);

/*
1. varianta
$pt = new ProgramThread(1, clone $program, clone $connection);
$pt->run();
exit;
*/

//2. varianta
$threads = [];
foreach (range(1, 1) as $i) {
    $threads[$i] = new ProgramThread($i, clone $program, clone $connection);
    $threads[$i]->start();
}

Dostanu:

Program | run
ProgramThread | __construct

Což je špatně, někam se vytrácí připojení předané modelu a nevím proč. Když odkomentuju variantu 1 a odmažu extends Thread, dostanu správný výsledek:

PDO | __construct
PDO | run

Co to může způsobovat?
David Klouček
Profil
Jednodušší příklad se skoro stejnym výstupem:

<?php
class Program {
    public $connection;
    public function run() {
        echo get_class($this->connection)." | run<br />\n";
    }
}
class Connection { //neserializovatelná třída
}
class ProgramThread extends Thread { //zkuste odmazat  "extends Thread" a bude to fungovat dobře
    public $program;
    public function __construct(Program $program, Connection $connection)
    {
        $this->program = $program;
        //$connection je v pořádku, ale do $this->program->connection se nechce zapsat
        $this->program->connection = $connection; // $this->program->connection je i po tomhle NULL
        echo get_class($this->program->connection)." | __construct<br />\n";
    } 

    public function run()
    {
        $this->program->run();
    }
}

$connection = new Connection();
$program = new Program;

$pt = new ProgramThread(clone $program, clone $connection);
$pt->run();
Alphard
Profil
Zkušenosti s tím bohužel nemám, ale po rychlém projití kódu mi to celé připadá jako snaha dostat do té knihovny něco, s čím nedokáže pracovat. To, že nejde connection předat přímo není bug, ale vlastnost. I když to interně neznám, ani se moc nedivím, že ten workaround selhává.

Viděl jste příklad na SQL worker? https://github.com/krakjoe/pthreads/blob/master/examples/SQLWorker.php hodně dotazů spojených s pthreads a databází vede sem.
Tady se teda připojení k db stále opakuje, což doporučuje i dokumentace...
Static Members: (...) For example, upon starting the context, a class whose static members include connection information for a database server, and the connection itself, will only have the simple connection information copied, not the connection. Allowing the new context to initiate a connection in the same way as the context that created it, storing the connection in the same place without affecting the original context.
(Zdroj http://php.net/manual/en/intro.pthreads.php)

Ovšem mysql extenzi má ještě další specifikat, a práce s MySQLi nebo PDO se řeší jinak.
Konkrétně s PDO je myslím docela relevantní příspěvek https://github.com/krakjoe/pthreads/issues/120#issuecomment-18869391 (což přesně odpovídá popisu v manuálu). Ukládání connection staticky je trochu dál posunuto u příkladu s MySQLi https://github.com/krakjoe/pthreads/blob/seven/examples/MySQLi.php. Tam je teda i pool, snad to půjde dát dohromady i s PDO.
pthreads tady momentálně nemám, takže to nemohu zkusit, ale předpokládám, že se Worker prostřednictvím Poolu 4x připojí k db a dále bude Pool Workery s jejich připojením recyklovat (protože Note that the link is stored statically, which for pthreads, means thread local).

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: