手机版

遇到php的in_array低性能问题

时间:2021-11-16 来源:互联网 编辑:宝哥软件园 浏览:

PHP的性能一直在提升。但是,如果使用不当,或者不小心,可能会踩到PHP内部实现的坑。前几天我遇到了一个性能问题。事情是这样的。一位同事报告说,我们的一个接口每次返回需要5秒。我们一起回顾代码,“惊奇”发现一个读缓存操作实际上是在循环中被调用的(大约900次),但是这个缓存的键并没有改变,所以我们把这个代码移出了循环,重新测试之后,接口的返回时间降到了2秒。喔!虽然翻了一倍,但显然不是我们能接受的结果!存在性能问题的代码量并不大。排除IO问题后,我们写了测试代码,问题很快又出现了。复制代码如下:php $ y=' 1800$ x=array();for($ j=0;$ j2000$ j){ $ x[]=' { $ j } ';} for($ I=0;$ i3000$i ){ if(in_array($y,$ x)){ continue;} } ?shell $ time/usr/local/PHP/bin/PHP test.php realm0 m 1.132s user 0m 1.118 ssy 0m 0.015s是的,我们使用的是字符串类型的数字,从缓存中取出时是这样的!所以特意转换成字符串(如果直接是数字就不会出现这个问题,可以自己验证)。可以看出花费的时间只有3000个周期,而sys后来花费的时间注定了我们用strace得不到任何有效的信息。壳牌$ strace-TTT-o XXX/usr/local/PHP/bin/PHP test.php壳牌$减去XXXin_array.strace

我们只看到这两个系统调用之间的延迟非常大,但我们不知道我们做了什么。无奈,好在Linux下的调试工具包括strace和ltrace(当然dtrace和ptrace不在本文范围内,此处省略)。参考:strace用于跟踪进程的系统调用或信号生成,而LTACE用于跟踪进程调用库函数(通过IBM developerworks)。为了消除干扰因素,我们直接把$x赋给数组的形式(“0”、“1”、“2”,)以避免过多的malloc调用影响结果。执行shell $ ltrace-c/usr/local/PHP/bin/PHP test.php,如图2所示。

我们看到库函数__strtol_internal调用非常频繁,达到94%,太夸张了。然后我查了库函数__strtol_internal是干什么用的。它原来是strtol的别名,简单来说就是把字符串转换成长的形状。我们可以猜测PHP引擎已经检测到它是一个字符串类型的数字。因此,我们希望将它们转换成长整数进行比较。这个转换过程消耗了太多时间。当我们再次执行: copy代码时,代码如下: shell $ ltrace-e ' _ _ strtol _ internal '/usr/local/PHP/bin/PHP test.php可以很容易地捕捉到如下图所示的大量调用。问题已经找到了。in_array是一个松散的比较,将两个字符类型的数字字符串转换成长整数,然后进行比较,但是性能会在不知情的情况下被消耗掉。tu3

知道了问题的关键,我们有很多解决办法。最简单的方法是将第三个参数作为true添加到in_array中,即同时进行严格的比较和类型比较。这就避免了PHP对类型的巧妙转换,它确实运行得更快。代码如下:复制代码如下:php $ y=' 1800$ x=array();for($ j=0;$ j2000$ j){ $ x[]=' { $ j } ';} for($ I=0;$ i3000$i ){ if(in_array($y,$x,true)){ continue;}}?复制代码如下: shell $ time/usr/local/PHP/bin/PHP test.php realm0.267 s userm0.247 s sys0m 0.020s快了很多倍!可以看出,sys的时间消耗变化不大。再一次,我们需要直接分配$x来消除malloc调用的干扰。因为我们实际上从缓存中拉出它一次,所以在示例代码中没有这样的循环来应用内存。再次执行复制代码如下: shell $ ltrace-c/usr/local/PHP/bin/PHP test.php如下所示: in_array.ltrace2

__ctype_tolower_loc耗时最多!检查库函数__ctype_tolower_loc的作用:简单的理解是将字符串转换为小写,那么这是否意味着in_array比较字符串不区分大小写呢?实际上,这个函数调用与我们的in_array感觉几乎没有什么联系。至于in_array的实现,我们应该看看PHP的源代码。我们可能理解得更透彻。我们不能继续了。欢迎与我交流。请改正任何错误。3354——————2013年8月29日的分割线是——3——33543354333——。晚上,PHP 5.4.10下面的源代码又被翻了一遍。我对in_array很感兴趣。哈哈,位于的1248线。/ext /ext/standard/array.c经过一番跟踪,在in_array比较松散的情况下,他为了比较而调用的函数zendi_smart_strcmp(其实是一个“智能”函数)位于。/Zend/zend_operators.c,以及我们用ltrace转换成整数时捕捉到的大量操作都是is_numeric_string_ex的行为。%E5%B1%8F%E5%B9%95%E5%BF%AB%E7%85%A7-2013-08-29-23.13.20

函数是在中定义的_numeric_string_ex。/Zend/Zend _ operators.h .经过大量的判断和转换,在第232行调用strtol,这就是我们在文章中提到的系统函数。它把字符串转换成长整数,有图有真zend_operators-is_num

版权声明:遇到php的in_array低性能问题是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。