php 7 mb_(多字节)函数比 5.3 慢 ~60%(仅限 Windows 问题)

标签 php performance php-7 php-7.1

我的应用程序大量使用了 mb_ 字符串函数,切换到 php 7 导致应用程序整体变慢。我追踪到 mb_ 字符串函数的问题。以下是基准代码和结果:

$time = microtime();
$time = explode(' ', $time);
$start = $time[1] + $time[0];
$startms = $time[0];
    for ($i=0; $i<100000; $i++) {
        $a = mb_strlen("fdsfdssdfoifjosdifjosdifjosdij:ά", "UTF-8");
    }
$time = microtime();
$time = explode(' ', $time);
$finish = $time[1] + $time[0];
$finishms = $time[0];
$total_time = round(($finish - $start), 4);
echo "mb_strlen: " . $total_time*1000 ." milliseconds<br/>";

$time = microtime();
$time = explode(' ', $time);
$start = $time[1] + $time[0];
$startms = $time[0];
    for ($i=0; $i<100000; $i++) {
        $a = mb_stripos("fdsfdssdfoifjosdifjosdifjosdij:ά", "α", 0, "UTF-8");
    }
$time = microtime();
$time = explode(' ', $time);
$finish = $time[1] + $time[0];
$finishms = $time[0];
$total_time = round(($finish - $start), 4);
echo "mb_stripos: " . $total_time*1000 ." milliseconds<br/>";


$time = microtime();
$time = explode(' ', $time);
$start = $time[1] + $time[0];
$startms = $time[0];
    for ($i=0; $i<100000; $i++) {
        $a = mb_substr("fdsfdssdfoifjosdifjosdifjosdij:ά", $i, 1, "UTF-8");
    }
$time = microtime();
$time = explode(' ', $time);
$finish = $time[1] + $time[0];
$finishms = $time[0];
$total_time = round(($finish - $start), 4);
echo "mb_substr: " . $total_time*1000 ." milliseconds<br/>";

平台为Windows 7 64位,IIS 7.5:

php 5.3.28
mb_strlen: 250 milliseconds
mb_stripos: 3078.1 milliseconds
mb_substr: 281.3 milliseconds

php 7.1.1
mb_strlen: 406.3 milliseconds
mb_stripos: 4796.9 milliseconds
mb_substr: 421.9 milliseconds

我不知道是我的设置有误还是什么,但多字节函数应该更慢似乎是不可思议的。关于为什么以及如何解决这个问题的任何想法?提前谢谢你。

编辑:正如 apokryfos 的评论所暗示的,这可能是 Windows 独有的问题。

最佳答案

我可以确认您的结果可在 Windows 7 上重现。 经过一些实验,我找到了一个快速的解决方案,IMO 应该甚至没有影响。

mb_strlen()可以看出函数签名, 如果省略编码参数,它将使用内部编码。 这也适用于您使用的其他功能。

mixed mb_strlen ( string $str [, string $encoding = mb_internal_encoding() ] )

我发现奇怪的是,如果您通过调用 mb_internal_encoding("UTF-8") 将内部编码设置为 UTF-8 并省略编码参数, 功能变得更快。

PHP 5.5 结果:

5.5.12

with encoding parameter:
- mb_strlen: 172 ms, result: 5
- mb_substr: 218 ms, result: う
- mb_strpos: 218 ms, result: 3
- mb_stripos: 1,669 ms, result: 3
- mb_strrpos: 234 ms, result: 3
- mb_strripos: 1,685 ms, result: 3

with internal encoding:
- mb_strlen: 47 ms, result: 5
- mb_substr: 78 ms, result: う
- mb_strpos: 62 ms, result: 3
- mb_stripos: 1,669 ms, result: 3
- mb_strrpos: 94 ms, result: 3
- mb_strripos: 1,669 ms, result: 3

PHP 7.0 结果:

7.0.12

with encoding parameter:
- mb_strlen: 640 ms, result: 5
- mb_substr: 702 ms, result: う
- mb_strpos: 686 ms, result: 3
- mb_stripos: 7,067 ms, result: 3
- mb_strrpos: 749 ms, result: 3
- mb_strripos: 7,130 ms, result: 3

with internal encoding:
- mb_strlen: 31 ms, result: 5
- mb_substr: 31 ms, result: う
- mb_strpos: 47 ms, result: 3
- mb_stripos: 7,270 ms, result: 3
- mb_strrpos: 62 ms, result: 3
- mb_strripos: 7,116 ms, result: 3

不幸的是,这个快速解决方案并不完美,因为 mb_stripos()mb_strripos() 似乎没有受到影响。 他们仍然很慢。

这是代码(缩写):

echo PHP_VERSION."\n";
echo "\nwith encoding parameter:\n";

$t = microtime(true)*1000;
for($i=0; $i<100000; $i++){
    $n = mb_strlen("あえいおう","UTF-8");
}
$t = microtime(true)*1000-$t;
echo "- mb_strlen: ".number_format($t)." ms, result: {$n}\n";

$t = microtime(true)*1000;
for($i=0; $i<100000; $i++){
    $n = mb_substr("あえいおう",-1,1,"UTF-8");
}
$t = microtime(true)*1000-$t;
echo "- mb_substr: ".number_format($t)." ms, result: {$n}\n";

//set internal encoding
//and omit encoding parameter

mb_internal_encoding("UTF-8");
echo "\nwith internal encoding:\n";

$t = microtime(true)*1000;
for($i=0; $i<100000; $i++){
    $n = mb_strlen("あえいおう");
}
$t = microtime(true)*1000-$t;
echo "- mb_strlen: ".number_format($t)." ms, result: {$n}\n";

$t = microtime(true)*1000;
for($i=0; $i<100000; $i++){
    $n = mb_substr("あえいおう",-1,1);
}
$t = microtime(true)*1000-$t;
echo "- mb_substr: ".number_format($t)." ms, result: {$n}\n";

关于php 7 mb_(多字节)函数比 5.3 慢 ~60%(仅限 Windows 问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45028018/

相关文章:

php - 如何在 Debian 上的 Apache 2.4 中为每个虚拟主机选择 PHP 版本 5 和 7?

php - Laravel Redirect->with(key, val) 不工作

php - 使用 jQuery 添加表单字段和 PHP Session 来记住添加的字段

php - 根据先前的字段答案自动填充下一个选择框

php - 使用 Yii CActiveDataProvider 时如何将 2 个模型与关系连接起来

java - JMeter:获取发布请求 URL 和数据

PHP7 + Symfony 2.8,写入 session 数据失败

php - 将两个表连接到一个数据库中

javascript - 如何针对 IE 进行优化?

java - 复制java实例并存储在第一个实例中,如何将第二个实例的值复制回第一个实例?