我有使用类Model的类程序。现在我需要在多个线程中运行Program,但它不能正常工作。我的代码是:
$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"; //returns 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;
$program->setModel($model);
现在我在多个线程中运行它:
$threads = [];
foreach (range(1, 1) as $i) { //only 1 thread for example
$threads[$i] = new ProgramThread($i, clone $program, clone $connection);
$threads[$i]->start();
}
它返回错误的类名Program和ProgramThread而不是预期的PDO。
Program | run
ProgramThread | __construct
当我删除&#34;扩展线程&#34;从第一个代码开始运行:
$pt = new ProgramThread(1, clone $program, clone $connection);
$pt->run();
它返回正确的结果:
PDO | __construct
PDO | run
问题出在哪里?
以下是具有相同输出的简单示例:
class Program {
public $connection;
public function run() {
echo get_class($this->connection)." | run<br />\n";
}
}
class Connection { //unserializable class
}
class ProgramThread extends Thread { //try deleting "extends Thread"
public $program;
public function __construct(Program $program, Connection $connection)
{
$this->program = $program;
$this->program->connection = $connection;
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();
答案 0 :(得分:1)
您尝试做的事情有几个问题:
正式不支持资源,您要做的是为每个线程使用PDO对象,仅将连接参数传递给线程。即使偶然的驱动程序碰巧使用pthreads,使用它也不安全,你必须为每个线程创建一个连接。
<?php
class Program {
public function run() {
echo get_class($this->connection)." | run<br />\n";
}
}
class Connection {}
class ProgramThread extends Thread {
public function __construct(Program $program, Connection $connection)
{
$program->connection = $connection;
$this->program = $program;
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();
请注意,这会给出您期望的输出,因为在序列化对象以进行存储之前已设置连接。
这仍然是一个可怕的代码,当您为PDO交换示例对象时,它不会像您期望的那样运行。
<?php
class PDOWorker extends Worker {
public function __construct(array $config) {
$this->config = $config;
}
public function run() {
self::$connection =
new PDO(...$this->config);
}
private $config;
public static $connection;
}
$pool = new Pool(4, PDOWorker::class, [["sqlite:example.db"]]);
while (@$i++<10) $pool->submit(new class extends Collectable {
public function run() {
if (PDOWorker::$connection) {
printf("Got connection from %s in Thread #%lu\n",
get_class($this->worker),
Thread::getCurrentThreadId());
}
}
});
$pool->shutdown();
?>
将输出如下内容:
Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458210621184
Got connection from PDOWorker in Thread #140458234603264
Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458223204096
Got connection from PDOWorker in Thread #140458234603264
Got connection from PDOWorker in Thread #140458210621184
Got connection from PDOWorker in Thread #140458198038272
Got connection from PDOWorker in Thread #140458198038272
PHP7代码,因为世界正在发展......如果你想看PHP5代码,你可以向后推断......
注意PDO对象如何存储在静态类成员中,这些对象被pthreads视为线程本地,并且从不被序列化。因此,每个线程都有自己的连接,一切都按预期运行,并且您正在按预期使用驱动程序。