我目前有一些PHP代码,基本上从xml文件中提取数据并使用$products = new SimpleXMLElement($xmlString)创建简单的xml对象;然后我使用for循环遍历此代码,在其中我为XML文档中的每个产品设置产品详细信息.然后将其保存到MysqL数据库.
在运行此脚本时,添加的产品会降低频率,直到它们最终在达到最大值之前停止.我试过间隔运行垃圾收集,但无济于事.以及取消设置似乎不起作用的各种变量.
部分代码如下所示:
<?PHP
$servername = "localhost";
$username = "database.database";
$password = "demwke";
$database = "databasename";
$conn = new MysqLi($servername, $username, $password, $database);
$file = "large.xml";
$xmlString = file_get_contents($file);
$products = new SimpleXMLElement($xmlString);
unset($xmlString, $file);
$total = count($products->datafeed[0]);
echo 'Starting<br><br>';
for($i=0;$i<$total;$i++){
$id = $products->datafeed->prod[$i]['id'];
etc etc
$sql = "INSERT INTO products (id, name, uid, cat, prodName, brand, desc, link, imgurl, price, subcat) VALUES ('$id', '$store', '$storeuid', '$category', '$prodName', '$brand', '$prodDesc', '$link', '$image', '$price', '$subCategory')";
}
echo '<br>Finished';
?>
PHP变量都是使用与$id类似的行定义的,但是为了便于阅读而删除.
关于我能做什么/读什么来完成这个的任何想法?只要它最终完成,所花费的时间对我来说并不重要.
解决方法:
更新:除非您的对象非常少,否则永远不要使用SimpleXML索引.使用foreach代替:
// Before, with [index]:
for ($i=0;$i<$total;$i++) {
$id = $products->datafeed->prod[$i]['id'];
...
// After, with foreach():
$i = 0;
foreach ($products->datafeed->prod as $prod) {
$i++; // Remove if you don't actually need $i
$id = $prod['id'];
...
通常,…… – >节点[$i]将访问数组node []并将其全部读取到所需的索引,因此迭代节点数组不是o(N),而是o(N2).没有解决方法,因为无法保证当您访问项目K时,您刚刚访问了项目K-1(以递归方式等). foreach保存指针,因此工作在o(N).
出于同样的原因,即使你真的只需要很少的已知项目(除非它们很少并且非常接近数组的开头),使用foreach整个数组进行迭代可能是有利的:
$a[0] = $products->datafeed->prod[15]['id'];
...
$a[35] = $products->datafeed->prod[1293]['id'];
// After, with foreach():
$want = [ 15, ... 1293 ];
$i = 0;
foreach ($products->datafeed->prod as $prod) {
if (!in_array(++$i, $want)) {
continue;
}
$a[] = $prod['id'];
}
您应首先验证增加的延迟是由MysqLi还是由XML处理引起的.您可以从循环中删除(注释掉)SQL查询执行,而不是其他任何内容,以验证速度(授予它现在将高得多…… :-))现在保持不变,或者显示相同的减少.
我怀疑XML处理是罪魁祸首,在这里:
for($i=0;$i<$total;$i++){
$id = $products->datafeed->prod[$i]['id'];
…在哪里访问一个SimpleXMLObject越来越远的索引.这可能会遇到Schlemiel the Painter的问题.
您的问题的直接答案是“如何让循环完成,无论时间”,“增加内存限制和最大执行时间”.
$i = -1;
foreach ($products->datafeed->prod as $prod) {
$i++;
$id = $prod['id'];
...
}
试验
// Stage 1. Create a large XML.
$xmlString = '<?xml version="1.0" encoding="UTF-8" ?>';
$xmlString .= '<content><package>';
for ($i = 0; $i < 100000; $i++) {
$xmlString .= "<entry><id>{$i}</id><text>The quick brown fox did what you would expect</text></entry>";
}
$xmlString .= '</package></content>';
// Stage 2. Load the XML.
$xml = new SimpleXMLElement($xmlString);
$tick = microtime(true);
for ($i = 0; $i < 100000; $i++) {
$id = $xml->package->entry[$i]->id;
if (0 === ($id % 5000)) {
$t = microtime(true) - $tick;
print date("H:i:s") . " id = {$id} at {$t}\n";
$tick = microtime(true);
}
}
在生成XML之后,循环会解析它并打印迭代5000个元素所需的量.为了验证它确实是时间增量,还会打印日期. delta应该大约是时间戳之间的时间差.
21:22:35 id = 0 at 2.7894973754883E-5
21:22:35 id = 5000 at 0.38135695457458
21:22:38 id = 10000 at 2.9452259540558
21:22:44 id = 15000 at 5.7002019882202
21:22:52 id = 20000 at 8.0867099761963
21:23:02 id = 25000 at 10.477082967758
21:23:15 id = 30000 at 12.81209897995
21:23:30 id = 35000 at 15.120756149292
这就是发生的事情:处理XML数组变得越来越慢.
这与使用foreach的程序大致相同:
// Stage 1. Create a large XML.
$xmlString = '<?xml version="1.0" encoding="UTF-8" ?>';
$xmlString .= '<content><package>';
for ($i = 0; $i < 100000; $i++) {
$xmlString .= "<entry><id>{$i}</id><text>The quick brown fox did ENTRY {$i}.</text></entry>";
}
$xmlString .= '</package></content>';
// Stage 2. Load the XML.
$xml = new SimpleXMLElement($xmlString);
$i = 0;
$tick = microtime(true);
foreach ($xml->package->entry as $data) {
// $id = $xml->package->entry[$i]->id;
$id = $data->id;
$i++;
if (0 === ($id % 5000)) {
$t = microtime(true) - $tick;
print date("H:i:s") . " id = {$id} at {$t} ({$data->text})\n";
$tick = microtime(true);
}
}
时间似乎是不变的……我说“似乎”因为它们似乎减少了大约一万倍,而且我在获得可靠的测量方面遇到了一些困难.
(不,我不知道.我可能从未使用过大型XML数组的索引).
21:33:42 id = 0 at 3.0994415283203E-5 (The quick brown fox did ENTRY 0.)
21:33:42 id = 5000 at 0.0065329074859619 (The quick brown fox did ENTRY 5000.)
...
21:33:42 id = 95000 at 0.0065121650695801 (The quick brown fox did ENTRY 95000.)