gpt4 book ai didi

PHP 线程 SimpleXMLElement

转载 作者:可可西里 更新时间:2023-10-31 22:11:56 28 4
gpt4 key购买 nike

我到处搜索这个,我遇到了很多问题,但我不认为这是实际代码的问题。基本上这段代码在两个单独的线程中启动套接字服务器(登录和游戏),我基本上是从非线程版本转换这段代码,但我一直无法让它为线程工作。

include "socket.php";
include "dep.php";

class Server extends Thread {
public $server;
public $config;
public function __construct($type){
//$this->config = (string)$type;
$this->run2($type);
$this->run();
}
public function run(){
while(true){
$this->server->loop();
}
}
public function run2($config){
$this->server = new sokserv($config);
$this->server->init();
//while(true){
// $this->server->loop();
//}
}
}
$login = new Server('Config/config.xml');
$game = new Server("Config/config2.xml");
The error received is
Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'SimpleXMLElement' is not allowed' in C:\Users\=\Desktop\Test\Start.php:19
Stack trace:
#0 C:\Users\=\Desktop\Test\Start.php(19): Server->run2()
#1 C:\Users\=\Desktop\Test\Start.php(10): Server->run2('Config/config.x...')
#2 C:\Users\=\Desktop\Test\Start.php(26): Server->__construct('Config/config.x...')
#3 {main}
thrown in C:\Users\=\Desktop\Test\Start.php on line 19

但是,恢复到旧代码可以正常工作。sokserv的第一部分(我删除了一些公共(public)变量,因为它们包含个人信息)

class sokserv
{
public $ip;
public $port;
public $users = array();
public $config;
public $mysql;
private $socket;
public function __construct($config = "Config/config.xml")
{
$this->readConfig($config);
}
public function readConfig($file)
{
if (!file_exists($file))
die("Could not find config");
$this->config = simplexml_load_file($file);
}

如果你想要,这是 xml:

<server>
<port>6112</port>
<ip>0</ip>
<mysql>
<host>127.0.0.1</host>
<username>root</username>
<dbname></dbname>
<password></password>
<table></table>
</mysql>
</server>

最佳答案

在 TSRM 的帮助下,Zend 内存管理器专门用于禁止上下文共享数据;没有上下文可以在另一个线程中分配或释放任何东西。这被称为无共享架构,它完全按照 jar 上说的做。 pthread 的工作是以安全、理智的方式突破这个障碍。

显然,与 PHP 捆绑在一起的扩展都不知道 pthreads,我们也不希望它们知道,因为它们只会变得非常复杂。当涉及到其他扩展提供的对象时,pthreads 假设最安全的做法是序列化对象以进行存储。一些对象禁止这种情况发生,SimpleXML后代就是这样一组对象。

从 pthread 派生的字符串、 float 、整数和对象不会被序列化。来自 pthreads 的对象劫持序列化 API,存储对象的物理地址,通过直接访问表示用户空间中对象的线程安全结构来避免序列化。

正确的解决方案是将您希望共享的数据包装在 pthreads 派生的对象中:

<?php
class Config extends Stackable {
/**
* Constructs thread safe, sharable configuration from complex XML
* @param mixed $xml SimpleXMLElement or location of XML file
* @param array &$objects reference store
*/
public function __construct($xml, &$objects) {
if ($xml instanceof SimpleXMLElement) {
foreach ($xml as $key => $value)
$this[$key] = (string) $value;
} else {
foreach (simplexml_load_string(
$xml) as $key => $value) {
if ($value->children()) {
$this[$key] = new Config($value, $objects);
} else $this[$key] = (string) $value;
}
}

/* maintain object references */
$objects[] = $this;
}

public function run() {}
}

class Test extends Thread {
protected $config;

/**
* Constructs thread using pre-constructed thread safe, shared configuration object
* @param Config $config
*/
public function __construct(Config $config) {
$this->config = $config;
}

public function run() {
/* iterate over configuration */
printf("%d settings:\n", count($this->config));
foreach ($this->config as $key => $data) {
if (count($data) > 1) {
printf(
"\t%s, %d settings:\n", $key, count($data));
foreach ($data as $name => $value) {
printf("\t\t%s = %s\n", $name, $value);
}
} else printf("\t%s = %s\n", $key, $data);
}
printf("\n");

printf(
"Host: %s:%d\n",
$this->config->ip,
$this->config->port);

printf(
"MySQL: %s@%s?database=%s&password=%s&table=%s\n",
$this->config->mysql->username,
$this->config->mysql->host,
$this->config->mysql->dbname,
$this->config->mysql->password,
$this->config->mysql->table);
}
}

/* Example XML */
$xml = <<<XML
<server>
<port>6112</port>
<ip>some.ip</ip>
<mysql>
<host>127.0.0.1</host>
<username>root</username>
<dbname>somedb</dbname>
<password>somepass</password>
<table>sometable</table>
</mysql>
</server>
XML;

/* Object reference storage */
$objects = [];
$config = new Config($xml, $objects);

$thread = new Test($config);
$thread->start();

$thread->join();
?>

将输出如下:

3 settings:
port = 6112
ip = some.ip
mysql, 5 settings:
host = 127.0.0.1
username = root
dbname = somedb
password = somepass
table = sometable

Host: some.ip:6112
MySQL: root@127.0.0.1?database=somedb&password=somepass&table=sometable

提供的示例使用您在问题中提供的 [格式] XML,它采用该 XML 并创建它的线程安全表示,永远不会被序列化。

Config 构造函数中的逻辑完全取决于您使用的 XML 格式。

您可以将该 Config 对象传递给任意数量的线程,所有线程都可以读/写属性,并执行它的方法。

您打算共享的所有数据都应该以这种方式管理,您想要从中得到的不是您应该解决异常并尝试存储串行数据,而是您应该为您的数据创建合适的容器,这些容器实际上正确地支持多线程

进一步阅读:https://gist.github.com/krakjoe/6437782

关于PHP 线程 SimpleXMLElement,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21174603/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com