php字符串是不可变的吗?

2022-08-31 00:42:10

或者:我应该在PHP中优化我的字符串操作吗?我试图问PHP的手册,但我没有得到任何提示。


答案 1

PHP已经对其进行了优化 - 变量是使用写入时复制分配的,并且对象是通过引用传递的。在 PHP 4 中,它没有,但无论如何,没有人应该使用 PHP 4 作为新代码。


答案 2

在许多语言中,最重要的速度优化技术之一是实例重用。在这种情况下,速度的提高至少来自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 实现是可用的。相同的算法可以(已经由我)推广以加速任意精度整数的乘法。


推荐