php字符串是不可变的吗?
或者:我应该在PHP中优化我的字符串操作吗?我试图问PHP的手册,但我没有得到任何提示。
在许多语言中,最重要的速度优化技术之一是实例重用。在这种情况下,速度的提高至少来自2个因素:
1. 更少的实例化意味着更少的构建时间。
2. 应用程序使用的内存量越少,CPU 缓存未命中率就越低。
对于速度是第一优先级的应用程序,CPU和RAM之间存在真正严格的瓶颈。瓶颈的原因之一是RAM的延迟。
PHP,Ruby,Python等与缓存未命中有关,因为它们甚至在RAM中存储了至少一些(可能是全部)解释程序的运行时数据。
字符串实例化是经常完成的操作之一,相对“大量”,它可能会对速度产生明显影响。
以下是测量实验的run_test.bash:
#!/bin/bash
for i in `seq 1 200`;
do
/usr/bin/time -p -a -o ./measuring_data.rb php5 ./string_instantiation_speedtest.php
done
以下是 ./string_instantiation_speedtest.php 和测量结果:
<?php
// The comments on the
// next 2 lines show arithmetic mean of (user time + sys time) for 200 runs.
$b_instantiate=False; // 0.1624 seconds
$b_instantiate=True; // 0.1676 seconds
// The time consumed by the reference version is about 97% of the
// time consumed by the instantiation version, but a thing to notice is
// that the loop contains at least 1, probably 2, possibly 4,
// string instantiations at the array_push line.
$ar=array();
$s='This is a string.';
$n=10000;
$s_1=NULL;
for($i=0;$i<$n;$i++) {
if($b_instantiate) {
$s_1=''.$s;
} else {
$s_1=&$s;
}
// The rand is for avoiding optimization at storage.
array_push($ar,''.rand(0,9).$s_1);
} // for
echo($ar[rand(0,$n)]."\n");
?>
我从这个实验和我用 Ruby 1.8 做的另一个实验中得出的结论是,通过引用传递字符串值是有意义的。
允许“按引用传递字符串”在整个应用程序范围内发生的一种可能方法是,每当需要使用字符串的修改版本时,始终创建新的字符串实例。
为了增加局部性,从而增加速度,可能需要减少每个操作数消耗的内存量。以下实验演示了字符串串联的情况:
<?php
// The comments on the
// next 2 lines show arithmetic mean of (user time + sys time) for 200 runs.
$b_suboptimal=False; // 0.0611 seconds
$b_suboptimal=True; // 0.0785 seconds
// The time consumed by the optimal version is about 78% of the
// time consumed by the suboptimal version.
//
// The number of concatenations is the same and the resultant
// string is the same, but what differs is the "average" and maximum
// lengths of the tokens that are used for assembling the $s_whole.
$n=1000;
$s_token="This is a string with a Linux line break.\n";
$s_whole='';
if($b_suboptimal) {
for($i=0;$i<$n;$i++) {
$s_whole=$s_whole.$s_token.$i;
} // for
} else {
$i_watershed=(int)round((($n*1.0)/2),0);
$s_part_1='';
$s_part_2='';
for($i=0;$i<$i_watershed;$i++) {
$s_part_1=$s_part_1.$i.$s_token;
} // for
for($i=$i_watershed;$i<$n;$i++) {
$s_part_2=$s_part_2.$i.$s_token;
} // for
$s_whole=$s_part_1.$s_part_2;
} // else
// To circumvent possible optimization one actually "uses" the
// value of the $s_whole.
$file_handle=fopen('./it_might_have_been_a_served_HTML_page.txt','w');
fwrite($file_handle, $s_whole);
fclose($file_handle);
?>
例如,如果一个人组装了包含大量文本的HTML页面,那么人们可能需要考虑顺序,即生成的HTML的不同部分是如何连接在一起的。
BSD 许可的 PHP 实现和分水岭字符串串联算法的 Ruby 实现是可用的。相同的算法可以(已经由我)推广以加速任意精度整数的乘法。