0

我在大型 PHP 应用程序的特定部分遇到了一个相当奇怪的问题。有问题的应用程序部分从 MySQL 加载数据(主要是整数数据)并构建一个 JSON 字符串,该字符串将输出到浏览器。这些请求在 Chrome 的开发人员工具中以及通过curl. 然而,我报告的 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]))

解决问题。为什么是这样?

4

0 回答 0