购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.19 提前计算循环长度

1.优化前后的对比

在进入一个循环之前计算长度是另一项可以优化的技术。以下代码是一个简单的for循环,它将遍历数组$item并分10次计算出数值,以确定哪些地方可以进行优化。代码清单1-28如下所示:

代码清单1-28 未优化的for循环


<php
$items = array12345678910);
for$i=10$i<count$items);$i++{
    $x = 1999 * $i
}>

我们主要注意for循环的逻辑,PHP按以下方式来执行此循环。

(1)初始化$i变量为0,从索引0开始循环,使用count()函数计算数组长度,$i计数器加1。

(2)迭代0完成后,开始索引1,使用count()计算数组长度,$i计数器加1。

(3)迭代1完成后,开始索引2,使用count()计算数组长度,$i计数器加1。

代码继续运行,直到到达数组元素的末尾。这段代码在开始时,问题便存在了。每次开始一个新索引的循环时,都必须调用函数count()来确定数组长度。上面的代码中,count()被调用了10次,其中有9次是多余的,因此这些不必要的调用需要替换,只要到达for循环之前调用一次count()就可以了。

那么修正优化后的for循环如代码清单1-29所示:

代码清单1-29 优化后的for循环


<php
$items = array12345678910);
$count = count$items);
for$i=10$i<$count$i++{
    $x = 1999 * $i
}>

上面的代码产生的结果与前一个代码清单的执行结果相同,但是函数的调用次数却从10次降到了1次,很明显的道理,调用的次数越少,PHP执行的程度就越快。

2.计算优化节省的时间

为了准确计算出减少9次count()函数调用能够节省多少时间,我们可以使用microtime()。在代码清单1-30中,增加另一个for循环,执行该代码10万次,代表有10万个用户来请求该脚本。我们对有变动的代码以粗体表示出来。

代码清单1-30 未优化的for循环基准代码


<php
$items = array12345678910);
$start = microtime();
for$x = 0 $x<100000 $x++){
    for$i=10$i<count$items);$i++{
        $x = 1999 * $i
    }
}
echo microtime()-$start
   >

执行10次该代码并计算结果的平均值,我们得出,10万次循环的总执行时间为0.046 ms。重新启动Web服务器,现在我们测试上面优化后的代码,如代码清单1-31所示:

代码清单1-31 优化后的for循环基准代码


<php
$items = array12345678910);
$count = count$items);
$start = microtime();
for$x = 0 $x<100000 $x++){
    for$i=10$i<$count$i++{
        $x = 1999 * $i
    }
}
echo microtime()-$start
   >

我们再次运行10次代码并获取平均值,使用此代码我们会看到,for循环的平均执行时间为0.0095 ms,减少了0.036 ms,即优化过的代码快了0.036 ms。

3.使用foreach替代for和while循环

访问数组数据的方法也是可以优化的,那就是尽量使用foreach语句,让它来替代while和for循环。

优化数据访问的方法对性能来讲很重要。许多Web应用需要从数据库、XML、JSON文件中读取数据并必须遍历每条记录后才能将数据显示给用户,能减少一毫秒等待,对于产品和用户来说,都有很重要的价值。

还是使用实例来说明这种优化之细节,如代码清单1-32所示:

代码清单1-32 使用foreach语句


<php
$items = array_fill0100000,’12345678910’);
$start = microtime();
reset$items);
foreach$items as $item
{
    $x = $item
}
echo microtime()-$start
   >

该脚本创建了一个数组$items,其中包含10万个元素,每个元素含有155个字节的字符串,代表数据库中典型数据。之后该代码设置了开始时间并使用foreach循环访问数组的每个元素,最后我们以毫秒为单位显示所用时间。我们连续执行了10次上面的代码清单,然后计算出每次执行时间的平均值,其结果为0.0078ms。

我们以上面的代码为基础,使用while循环,而不是foreach循环。代码清单粗体部分为我们对其做的修改,如代码清单1-33所示:

代码清单1-33 使用while循环


<php
$items = array_fill0100000,’12345678910’);
$start = microtime();
reset$items);
$i=0
while$i<100000{
    $x = $items[$i]
    $i++
}
echo microtime()-$start
   >

重新启动Web服务器,运行该代码10次以后,我们再次计算平均执行时间。用while循环访问数组中单个元素的平均时间为0.0099 ms。

下面我们再来比较一下使用for循环,如代码清单1-34所示。我们按照同样的基准循环流程,重启Web服务器,执行代码10次并计算平均结果。

代码清单1-34 使用for循环


<php
$items = array_fill0100000,’12345678910’);
$start = microtime();
reset$items);
$i=0
for$i=0$i<100000$i++{
    $j = $items[$i]
}
echo microtime()-$start
   >

我们将上述3种循环基准的结果总结在表1-4中。

表1-4 10个元素数组的PHP循环平均执行时间

由此可见,使用foreach循环是访问数组元素性能最优之方法。感兴趣的朋友也可以自己来尝试一下。 URGrPr3hu5C3tLs1Bwv5e9RwaoVQsNwkXdsazcQwOcBEgCGk1hw6yCz6CMHidFQ+

点击中间区域
呼出菜单
上一章
目录
下一章
×