【问题标题】:What is the best way to add two strings together?将两个字符串加在一起的最佳方法是什么?
【发布时间】:2010-10-16 06:12:20
【问题描述】:

我在某处读到(我想到了编码恐怖),将字符串添加在一起就像它们是数字一样是不好的做法,因为与数字一样,字符串不能更改。因此,将它们加在一起会创建一个新字符串。所以,我想知道,在关注性能时,将两个字符串相加的最佳方法是什么?

这四个哪个更好,或者还有其他更好的方法吗?

//Note that normally at least one of these two strings is variable
$str1 = 'Hello ';
$str2 = 'World!'; 
$output1 = $str1.$str2; //This is said to be bad

$str1 = 'Hello ';
$output2 = $str1.'World!'; //Also bad

$str1 = 'Hello';
$str2 = 'World!';
$output3 = sprintf('%s %s', $str1, $str2); //Good?
//This last one is probaply more common as:
//$output = sprintf('%s %s', 'Hello', 'World!');

$str1 = 'Hello ';
$str2 = '{a}World!';
$output4 = str_replace('{a}', $str1, $str2);

这还重要吗?

【问题讨论】:

标签: php performance string


【解决方案1】:

从 Google 找到这篇文章,并认为我会运行一些基准测试,因为我很好奇结果会是什么。 (使用减去自身开销的基准测试器对超过 10,000 次迭代进行基准测试。)

其中 2 弦 10 弦 50 弦 -------------------------------------------------- -------------- $a[] 然后 implode() 2728.20 ps 6.02 μs 22.73 μs $一个。 $一个。 $a 496.44 皮秒 1.48 微秒 7.00 微秒 $b .= $a 421.40 ps ★ 1.26 μs 5.56 μs ob_start() 和 echo $a 2278.16 ps 3.08 μs 8.07 μs "$a$a$a" 482.87 ps 1.21 μs ★ 4.94 μs ★ sprintf() 1543.26 ps 3.21 微秒 12.08 微秒

所以内容不多。如果您需要快速尖叫,最好避免使用sprintf()implode(),但所有常用方法之间没有太大区别。

【讨论】:

    【解决方案2】:

    这是快速而肮脏的测试代码,以了解性能瓶颈。

    单连接:

    $iterations = 1000000;
    $table = 'FOO';
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = sprintf('DELETE FROM `%s` WHERE `ID` = ?', $table);
    }
    echo 'single sprintf,',(microtime(true) - $time)."\n";
    
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = 'DELETE FROM `' . $table . '` WHERE `ID` = ?';
    }
    echo 'single concat,',(microtime(true) - $time)."\n";
    
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = "DELETE FROM `$table` WHERE `ID` = ?";
    }
    echo 'single "$str",',(microtime(true) - $time)."\n";
    

    我得到了这些结果:

    single sprintf,0.66322994232178
    single concat,0.18625092506409 <-- winner
    single "$str",0.19963216781616
    

    许多连接(10):

    $iterations = 1000000;
    $table = 'FOO';
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = sprintf('DELETE FROM `%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s`,`%s` WHERE `ID` = ?', $table, $table, $table, $table, $table, $table, $table, $table, $table, $table);
    }
    echo 'many sprintf,',(microtime(true) - $time)."\n";
    
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = 'DELETE FROM `' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '`,`' . $table . '` WHERE `ID` = ?';
    }
    echo 'many concat,',(microtime(true) - $time)."\n";
    
    $time = microtime(true);
    for ($i = 0; $i < $iterations; $i++) {
            $sql = "DELETE FROM `$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table`,`$table` WHERE `ID` = ?";
    }
    echo 'many "$str",',(microtime(true) - $time)."\n";
    

    结果:

    many sprintf,2.0778489112854
    many concats,1.535336971283
    many "$str",1.0247709751129 <-- winner
    

    作为结论,很明显通过点 (.) char 的单个 concat 是最快的。对于有很多 concat 的情况,最好的方法是通过 "injection: $inject" 语法使用直接字符串注入。

    【讨论】:

    • 好吧,我不会说“很明显,通过 dot (.) char 的单个 concat 是最快的”——在这样的微基准上,大约 10% 的时间差异实际上可以忽略不计。我想说,既然你证明了 "$str" 是连接数量增加的最快方法(有明显的 50% 时差),你应该说 "$str" 通常是连接字符串的首选方法。 ..
    【解决方案3】:

    有 3 种类型的字符串连接操作。

    连接,取2个字符串,分配内存大小length1+length2并将每个复制到新内存中。最快的 2 个字符串。但是,连接 10 个字符串需要 9 个连接操作。使用的内存是第 1 串 10 次、第 2 串 10 次、第 3 串 9 次、第 4 串 8 次等。每个循环使用更多内存运行 X+1 +(X-1)*2 操作。

    sprintf (array_merge, join, etc),把所有的字符串放在一起,对它们的长度求和,分配一个大小为 sum 的新字符串,然后将每个字符串复制到相应的位置。使用的内存是所有初始字符串的 2*length,操作是 2*X(每个长度,每个副本)

    ob(输出缓冲区)分配一个通用的 4k 块并将每个字符串复制到它。内存 4k + 每个初始字符串,操作 = 2 + X。(开始,结束,每个副本)

    选择你的毒药。 OB 就像使用内存原子弹连接 2 个小字符串,但是当有很多连接、循环、条件或添加对于干净的 sprintf 来说过于动态时非常有效。 concat 是连接几个固定字符串最有效的方法, sprintf 更适合一次性使用固定值构建字符串。

    我不知道在这种情况下 php 使用哪个例程:“$x $y $z”,可能只是简化为内联 $x 。 “”。 $y 。 “”。 $z

    【讨论】:

      【解决方案4】:

      在此线程上一次发布后近 2 年,我认为以下解决方案对于大量紧密循环可能是最快的:

      ob_start();
      
      echo $str1;
      echo $str2;
      .
      .
      .
      echo $str_n;
      
      $finalstr = ob_get_clean();
      

      此方法可确保所有字符串的平坦存储,并且没有处理或连接开销。使用最后的代码行,您也可以获得整个缓冲区。您可以安全地运行循环而不是独立的回显。

      【讨论】:

      • 但这意味着您在程序的这一部分中不能打印任何实际输出。这似乎是一个真正的组合,join 的答案可能也一样好。
      【解决方案5】:

      我不是 PHP 专家,但是,在许多其他语言(例如 Python)中,用许多较小的字符串构建长字符串的最快方法是将要连接的字符串附加到列表中,然后使用内置的连接方法加入它们。例如:

      $result = array();
      array_push("Hello,");
      array_push("my");
      array_push("name");
      array_push("is");
      array_push("John");
      array_push("Doe.");
      $my_string = join(" ", $result);
      

      如果你在一个紧密的循环中构建一个巨大的字符串,最快的方法是追加到数组,然后在最后加入数组。

      注意:整个讨论都取决于 array_push 的性能。您需要将您的字符串附加到一个 list 以便这对非常大的字符串有效。由于我对 php 的接触有限,我不确定这样的结构是否可用,或者 php 的数组是否能够快速添加新元素。

      【讨论】:

      • 这在 PHP 中速度较慢且 更多 内存密集。
      【解决方案6】:

      除非在 looong 循环中使用,否则没关系。在通常情况下,关注代码的可读性,即使您丢失了几个处理器周期。

      示例 1 和示例 2 类似,我认为应该没有太大区别,这将是所有禁食。 1 号可能会稍微快一些。

      示例 3 会比较慢,因为需要解析 sprintf 格式('%s %s')。

      示例 4 进行替换,这涉及在字符串中搜索 - 额外的事情要做,需要更多时间。

      但首先,连接字符串是性能问题吗?这不太可能,您应该分析代码以测量运行它需要多少时间。然后,一次又一次地用不同的方法替换连接方法。

      如果您认为这是一个问题,请尝试使用谷歌搜索 php string builder 类(有一些可以找到)或编写自己的。

      【讨论】:

        【解决方案7】:

        这不是 2 个字符串的解决方案,但是当您考虑以最好的方式连接更多字符串时:

        $tmp=srray();
        for(;;) $tmp[]='some string';
        $str=implode('',$tmp);
        

        创建数组元素并一次加入它们比加入它们一百次要快。

        【讨论】:

        • 我不得不承认。它更快,但在 JS,而不是 PHP 中,它仍然取决于浏览器。
        • 这是一个 PHP 问题。不是 JS 问题。
        【解决方案8】:

        除非它的文本量真的很大,否则真的没关系。

        【讨论】:

          【解决方案9】:

          带点的字符串连接绝对是三种方法中最快的一种。无论您喜欢与否,您总是会创建一个新字符串。 最快的方法很可能是:

          $str1 = "Hello";
          $str1 .= " World";

          不要将它们放在像$result = "$str1$str2"; 这样的双引号中,因为这会为解析字符串中的符号产生额外的开销。

          如果你只是想用 echo 来输出,那么使用 echo 的特性,你可以给它传递多个参数,因为这不会生成一个新的字符串:

          $str1 = "Hello";
          $str2 = " World";
          echo $str1, $str2;

          有关 PHP 如何处理内插字符串和字符串连接的更多信息check out Sarah Goleman's blog

          【讨论】:

            【解决方案10】:

            您阅读的建议可能与echo 函数有关,使用逗号会更快,例如:

            echo $str1, $str2;
            

            另一种方法是在变量中构建一个字符串(例如使用 . 运算符),然后在末尾回显整个字符串。

            您可以使用 microtime 函数自行测试(您需要创建一个循环,例如重复 1,000 或 100,000 次以使数字有意义)。但是在您发布的四个中,第一个可能是最快的。它也是最易读的——其他的在编程上真的没有意义。

            【讨论】:

              【解决方案11】:

              正如其他人所说,$str1 . $str2 在大多数情况下都可以,除了(大)循环。
              请注意,您忽略了一些解决方案:

              $output = "$str1$str2";
              

              对于大量的字符串,你可以将它们放在一个数组中,然后使用 implode() 从中取出一个字符串。

              哦,“添加字符串”听起来很糟糕,或者至少是模棱两可的。在大多数语言中,我们更喜欢谈论字符串连接。

              【讨论】:

              • 啊,好吧,我不是以英语为母语的人,所以我知道它有点像那个词,但我一直在集中注意力(这是一个完全不同的词(它甚至是一个词吗?))
              【解决方案12】:

              在将两个或多个字符串连接在一起时,您总是会创建一个新字符串。这不一定是“坏的”,但它在某些情况下可能会对性能产生影响(例如紧密循环中的数千/数百万个串联)。我不是一个 PHP 人,所以我不能就连接字符串的不同方式的语义给你任何建议,但是对于单个字符串连接(或只是几个),让它可读。你不会看到他们的数量很少会影响性能。

              【讨论】:

                猜你喜欢
                • 2012-03-15
                • 2016-01-03
                • 1970-01-01
                • 2014-09-04
                • 2011-10-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多