for循环关于对象长度优化思考

一、for循环对象长度两种写法

最近看到很多代码,各种语言,在写for循环的时候并没有把长度提取出来,而是每次遍历的时候进行计算。

$str = 'bye 2019, hi 2020!';
for ($i = 0; $i < strlen($str); $i++) {
    // do something
}

这种写法在初入行的时候,总是被教育性能低,要把长度提取出来。这个在诸多代码优化中总是排名榜首。

$str = 'bye 2019, hi 2020!';
$len = strlen($str);
for ($i = 0; $i < $len; $i++) {
    // do something
}

之前在大脑中空想,认为确实应该提取出来,省的每次遍历调用函数。最近正好有空,测试了以下,跟想象的差距很大。两种写法在数据量级小(小于10万)的时候,差异并不大。

二、性能测试

0、测试环境
OS: Mac

PHP版本
php -v
PHP 7.3.9 (cli) (built: Sep 14 2019 18:12:27) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.9, Copyright (c) 1998-2018 Zend Technologies
with Zend OPcache v7.3.9, Copyright (c) 1999-2018, by Zend Technologies

1、测试脚本
for_performance_v1.php

$stime = microtime(true);
$smem = memory_get_usage();
$multiplier = intval($argv[1]);
$s = str_repeat('bye2019,hi2020!', $multiplier);
for ($i = 0; $i < strlen($s); $i++) {
        echo $s[$i], PHP_EOL;
}

$etime = microtime(true);
$emem = memory_get_usage();
echo 'exec time : ', round(($etime - $stime), 3), PHP_EOL;
echo 'used memory(KB) : ', round(($emem - $smem) / 1024, 3), PHP_EOL;

for_performance_v2.php

$stime = microtime(true);
$smem = memory_get_usage();
$multiplier = intval($argv[1]);
$s = str_repeat('bye2019,hi2020!', $multiplier);
$len = strlen($s);
for ($i = 0; $i < $len; $i++) {
        echo $s[$i], PHP_EOL;
}

$etime = microtime(true);
$emem = memory_get_usage();
echo 'exec time : ', round(($etime - $stime), 3), PHP_EOL;
echo 'used memory(KB) : ', round(($emem - $smem) / 1024, 3), PHP_EOL;

2、脚本执行

php for_performance_v1.php 100000
php for_performance_v2.php 100000

3、性能结果
内存占用都一样,这里就不分开列出了。
+———–+——-+————+——+——+
| 长度 | v1 | v2 |内存 |
+———–+——-+————+——-+—–+
| 10000 | 0.429 | 0.477 | 148.031KB |
| 100000 | 3.923 | 3.283 | 1468.031KB |
| 100000 | 56.397| 40.27 | 14652.055KB |
+———–+——-+————+————-+

4、结果分析
这可能跟PHP运行时缓存有关。在执行期间,PHP经常需要根据名称去不同的哈希表中查找常量、函数、类、成员方法、成员属性等,因此PHP提供了一种缓存机制用于缓存根据名称查找到的结果,以便再次执行同一opcode时直接复用上次缓存的值,无需重复查找,从而提高执行效率。

三、总结思考

差距并没有我们想象中的大,6年的工作生产环境中,很少遇到超过10W的遍历。
多数人的错误,依旧是错误。代码的世界,实践比别人的结论更有意义。

参考:
PHP7内核剖析-运行时缓存

发表评论

电子邮件地址不会被公开。 必填项已用*标注