想知道是否有人可以帮助我解决我遇到的一个小问题
问题是负载可以达到5,并且CPU使用率可以达到40%,在具有356Mb RAM的双核“Xeon L5410 @ 2.33GHz”上,我不知道我应该在哪里调整代码以及防止这种情况的方法。下面的代码示例
//注意$ productFile可以是40Mb .gz压缩,700Mb未压缩(xml文本文件) if(file_exists($ productFile)){
$fResponse = gzopen($productFile, "r");
if ($fResponse) {
while (!gzeof($fResponse)) {
$sResponse = "";
$chunkSize = 10000;
while (!gzeof($fResponse) && (strlen($sResponse) < $chunkSize)) {
$sResponse .= gzgets($fResponse, 4096);
}
$new_page .= $sResponse;
$sResponse = "";
$thisOffset = 0;
unset($matches);
if (strlen($new_page) > 0) {
//Emptying
if (!(strstr($new_page, "<product "))) {
$new_page = "";
}
while (preg_match("/<product [^>]*>.*<\/product>/Uis", $new_page, $matches, PREG_OFFSET_CAPTURE, $thisOffset)) {
$thisOffset = $matches[0][1];
$thisLength = strlen($matches[0][0]);
$thisOffset = $thisOffset + $thisLength;
$new_page = substr($new_page, $thisOffset-1);
$thisOffset = 0;
$new_page_match = $matches[0][0];
//- Save collected data here -//
}
}//End while loop
}
}
gzclose($fResponse);
}
}
$ chunkSize - 它应该尽可能小以减少内存使用量并简化正则表达式,或者它应该更大以避免代码耗时太长而无法运行。
40,000匹配负载/ CPU峰值。所以,有人对如何通过crons管理大型Feed上传有任何建议。
提前感谢您的帮助
答案 0 :(得分:1)
你至少有两个问题。首先是您尝试将整个700 MB文件解压缩到内存中。事实上,你这样做了两次。
while (!gzeof($fResponse) && (strlen($sResponse) < $chunkSize)) {
$sResponse .= gzgets($fResponse, 4096);
}
$new_page .= $sResponse;
$sResponse
和$new_page
都将包含一个字符串,该字符串将包含整个700 MB文件。因此,当脚本运行时,你正在吃掉1.4 GB的内存,更不用说字符串连接的成本了(虽然PHP处理字符串比其他语言更好,但是mutable和non-mutable会有什么限制你)
第二个问题是你在$new_page
中越来越大的字符串上运行正则表达式。随着$new_page
越来越大,这将增加服务器的负担。
解决问题的最简单方法是分割任务。
在进行任何处理之前,将整个文件解压缩到磁盘。
使用基于 steram 的XML解析器,例如XMLReader
或旧SAX Event Based parser。
即使使用基于流/事件的解析器,将结果存储在内存中也可能会占用大量内存。在这种情况下,您需要将每个匹配项存储在磁盘/数据库中。
答案 1 :(得分:0)
既然你说你正在使用灯泡,我可以建议回答一个问题:Suggestions/Tricks for Throttling a PHP script
他建议在有问题的脚本上使用nice命令来降低它阻塞服务器的可能性。
另一种方法是分析脚本并查看任何瓶颈。我会推荐xdebug和kcachegrind或者webcachegrind。有无数的问题和网站可以帮助您设置脚本分析。
答案 2 :(得分:0)
您可能还想查看PHP的基于SAX事件的XML解析器 - http://uk3.php.net/manual/en/book.xml.php
这对于解析大型XML文件很有用(我们将它用于与您正在处理的类似大小的XML文件)并且它做得非常好。那么不需要正则表达式:)
在处理文件之前,您需要先解压缩文件。
答案 3 :(得分:0)
艾伦。该脚本永远不会在内存中保存700Mb,因为看起来$sResponse
在达到$ chunkSize后立即被清除并且已添加到$ new_page,
$new_page .= $sResponse;
$sResponse = "";
一旦找到每个匹配,和$new_page
将被删除,如果没有可能的匹配,则为每个$ chunkSize数据块清除。
$new_page = substr($new_page, $thisOffset-1);
if (!(strstr($new_page, "<product "))) {
$new_page = "";
}
虽然我不能说我能看出实际问题所在。