我遇到了一个与大型PHP应用程序的特定部分相当奇怪的问题。有问题的应用程序部分从MySQL加载数据(主要是整数数据)并构建一个JSON字符串,输出到浏览器。这些请求在Chrome的开发人员工具以及curl
中占用了sevar秒(每个8到10秒)。然而,PHP关闭处理程序我已经报告请求在不到1秒的时间内执行。
为了调试,我添加了对fastcgi_finish_request()
的调用,突然我的关机处理程序报告与Chrome / curl同时发生。
通过一些调试,我将其缩小到一个特定的功能。我创建了以下简单的测试用例:
<?php
$start_time = DFStdLib::exec_time();
$product = new ApparelQuoteProduct(19);
$pmatrix = $product->productMatrix();
// This function call is the problem:
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
如果我调用$pmatrix->ranges()
(这是一个对mysql_query
执行大量调用以获取数据并从该数据构建内存中的PHP对象结构的函数),那么我得到输出:
输出生成持续时间为:0.2563910484314秒; fastcgi_finish_request持续时间为:7.3854329586029秒
在我的日志文件中。请注意,对$pmatrix->ranges()
的调用并不需要很长时间,但不知何故,它会导致PHP FastCGI处理程序需要7秒才能完成请求。 (即使我不调用fastcgi_finish_request
也是如此 - 浏览器需要7-8秒才能显示数据)
如果我注释掉$pmatrix->ranges()
的电话,我会:
输出生成持续时间为:0.0016419887542725秒; fastcgi_finish_request持续时间为:0.00035214424133301秒
我可以发布$pmatrix->ranges()
函数的整个源代码,但它很长。我想在哪里开始寻找一些建议。
什么是PHP FastCGI请求进程甚至会导致这种行为?它是否调用析构函数/垃圾收集?它是否关闭开放资源?我该如何进一步解决这个问题?
编辑:这是一个更大的源样本:
<?php
class ApparelQuote_ProductPricingMatrix_TestCase
{
protected $myProductId;
protected $myQuantityRanges;
private $myProduct;
protected $myColors;
protected $mySizes;
protected $myQuantityPricing;
public function __construct($product)
{
$this->myProductId = intval($product);
}
/**
* Return an array of all ranges for this matrix.
*
* @return array
*/
public function ranges()
{
$this->myLoadPricing();
return $this->myQuantityRanges;
}
protected function myLoadPricing($force=false)
{
if($force || !$this->myQuantityPricing)
{
$this->myColors = array();
$this->mySizes = array();
$priceRec_finder = new ApparelQuote_ProductPricingRecord();
$priceRec_finder->_link = Module_ApparelQuote::dbLink();
$found_recs = $priceRec_finder->find(_ALL,"`product_id`={$this->myProductId}","`qtyrange_id`,`color_id`");
$qtyFinder = new ApparelQuote_ProductPricingQtyRange();
$qtyFinder->_link = Module_ApparelQuote::dbLink();
$this->myQuantityRanges = $qtyFinder->find(_ALL,"`product_id`=$this->myProductId");
$this->myQuantityPricing = array();
foreach ($found_recs as &$r)
{
if(false) $r = new ApparelQuote_ProductPricingRecord();
if(!isset($this->myColors[$r->color_id]))
$this->myColors[$r->color_id] = true;
if(!isset($this->mySizes[$r->size_id]))
$this->mySizes[$r->size_id] = true;
if(!is_array($this->myQuantityPricing[$r->qtyrange_id]))
$this->myQuantityPricing[$r->qtyrange_id] = array();
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id][$r->size_id] = &$r;
}
$this->myColors = array_keys($this->myColors);
$this->mySizes = array_keys($this->mySizes);
}
}
}
$start_time = DFStdLib::exec_time();
$pmatrix = new ApparelQuote_ProductPricingMatrix_TestCase(19);
$ranges = $pmatrix->ranges();
$end_time = DFStdLib::exec_time();
$duration = $end_time - $start_time;
echo "Output generation duration was: $duration sec";
fastcgi_finish_request();
$fastcgi_finish_request_duration = DFStdLib::exec_time() - $end_time;
DFSkel::log(DFSkel::LOG_INFO,"Output generation duration was: $duration sec; fastcgi_finish_request Duration was: $fastcgi_finish_request_duration sec");
继续调试后,我已经缩小到以上几行:
if(!is_array($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
$this->myQuantityPricing[$r->qtyrange_id][$r->color_id] = array();
这些语句构建了从MySQL加载的所有数据的内存数组结构。如果我评论这些,那么fastcgi_finish_request
大约需要0.0001秒才能运行。如果我不对它们进行评论,则fastcgi_finish_request
需要7秒以上才能运行。
is_array
的函数调用,这是更改为:
if(!isset($this->myQuantityPricing[$r->qtyrange_id][$r->color_id]))
解决了这个问题。这是为什么?