String camelize slow performance

时间:2016-05-06 11:38:35

标签: php

所以我在一个名为Camelize

的静态方法中有这段代码
return strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));

这只是骆驼化的东西。

我有大约211k的记录,迭代一段时间循环,theese记录有一些我需要登记的单词,最长的单词可以是大约10个字符,容易peasy,但运行一些xhprof测试我得出结论,camelize不是一个好主意如果你需要速度。

XHProf与camelize :313,866,303微秒(~5分钟)

  • 19,268,795次来电
  • 已包含壁垒时间228,658,500
  • ICpu:81.3%

没有驼峰的XHProf :5599,811微秒(<1分钟)

此脚本的目的是将值设置为类属性。

一个属性可以是protected $myVar,它是驼峰式的。

在我的构造函数中,我得到一个 下划线 属性(数组键)及其值(数组值)的数组。 my_var => foo

由于我们有camelized属性,我们需要将数组键转换为camelize,所以我们可以做类似的事情 $this->$camelizedProperty = $value

是的,我们本来可以使用下划线属性,所以我们不需要转换任何字符串,但这是一个旧的工作代码,现在它的属性大约是它的4倍,并且它被大量使用依赖关系,如果我们能找到一种加快camelizing的方法,那么现在不能将属性更改为下划线。

更新

使用microtime的某些单独测试来进行实时比较,我最终得到了这个......

使用的方法:

  1. strtr(ucwords(strtr($word, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''))
  2. lcfirst(str_replace(" ", "", ucwords(strtr($word, "_-", " "))))
  3. str_replace(" ", "", ucwords(strtr($word, "_-", " ")))
  4. 每次迭代超过~100个字符串的平均结果:

    1. 0.0011
    2. 0.0002
    3. 0.0002
    4. 正如@RST指出的那样,使用str_replace比我的第一个方法快18%,但仍然很慢(如果我们有一个巨大的循环)

      在20M记录中,使用xhprof,总结果为:

      1. 313秒(约5分钟)
      2. 152秒(~2.5min)
      3. 158秒(~2.5min)
      4. 我们可以说lcfirst不会减慢脚本速度(我认为这可能会导致一些较慢的时间)。

        这个问题不是关于如何驯化,而是关于它如何影响我们脚本中的性能,这可能是使用它的最佳方式。

1 个答案:

答案 0 :(得分:0)

那么,根据获得更快时间的重要性,您可以使用单个传递字符串迭代替换每个输入字符串的内置PHP函数调用。

2000万条记录的时间如下:

Method 1 time: 301.143823 
Method 2 time: 54.648126

不可否认,这里的代码可能看起来有点丑陋,但显然会缩短时间。注意,使用5个输入字符串只需将运行数量变量($ runqty)设置为4百万,以便为每个方法获得2000万个记录时序 - 请务必先在循环中注释掉echo语句。

示例代码......

<?php

$input = array();
$input['my_var'] = 'foo';
$input['this.that'] = 'blah';
$input['try\\me'] = 'strange';
$input['some_var_here'] = 'value';
$input['final_cut'] = 'fc99';

set_time_limit(600);

$runqty = 1;

// Method 1
$m1start = microtime(true);
for ($runs = 0; $runs < $runqty; $runs++)
{
  foreach ($input as $word => $val)
  {
    $out = strtr(ucwords(strtr($word, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));
    echo "in: $word out: $out<br>\n";
  }
}
$m1stop = microtime(true);
$m1time = $m1stop - $m1start;
echo "Method 1 time: " . sprintf("%0.6f",$m1time);
echo "<br>\n";

// Method 2
$m2start = microtime(true);
for ($runs = 0; $runs < $runqty; $runs++)
{
  foreach ($input as $word => $val)
  {
    $i=0;
    $len = strlen($word);
    $ucnext = true;
    $out = '';

    while ( $i < $len )
    {
      $char = $word[$i++];
      if ( $char == '_' || $char == '.' || $char == '\\' )
      {
        $ucnext = true;
        if ( $char == '.' )
          $char ='_';
        else
          $char = '';
      }
      else
      {
        if ( $ucnext )
        {
          if ( $char >= 'a' && $char <= 'z' )
            $char = ucfirst($char);
          $ucnext = false;
        }
      }

      $out .= $char;
    }
    echo "in: $word out: $out<br>\n";
  }
}
$m2stop = microtime(true);
$m2time = $m2stop - $m2start;
echo "Method 2 time: " . sprintf("%0.6f",$m2time);
echo "<br>\n";

注意:如果您不希望首字母大写,那么只需将ucnext变量初始化为false(而不是如图所示为true)。