更新:從來沒有使用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'];
...
一般而言,...->node[$i]
將訪問陣列node[]
並朗讀所有到所需的索引,以便迭代所述節點數組不是O(N),但O(N )。沒有解決方法,因爲不能保證當您訪問項目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'];
...
}
做實驗
我用這個小程序來讀取大型XML和重複的內容:
// 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個元素。爲了驗證它確實是時間增量,日期也被打印出來。增量應該近似於時間戳之間的時間差。
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.)
你能解釋一下「減少頻率直到它們最終停止嗎?也許添加一段XML結構來說明? –
我有另一頁用於檢查數據庫中的總行數。之後的第一個5秒約4000,然後再過5秒約2000新增自此以來。然後這會減少,直到它僅爲每秒10個左右。 –
可能的欺騙:http://stackoverflow.com/questions/18518602/stream-parse-4-gb-xml-file-in-php –