溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

如何解決php的in_array低性能問題

發(fā)布時間:2021-10-09 11:45:16 來源:億速云 閱讀:240 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“如何解決php的in_array低性能問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“如何解決php的in_array低性能問題”吧!

PHP的性能一直在提高。然而,若是用的不恰當(dāng),或是一個不留神,還是可能會踩到PHP內(nèi)部實現(xiàn)方面的坑的。

復(fù)制代碼 代碼如下:

<?php
$y="1800";
$x = array();
for($j=0;$j<2000;$j++){
$x[]= "{$j}";
}

for($i=0;$i<3000;$i++){
if(in_array($y,$x)){
continue;
}
}
?>


shell$ time /usr/local/php/bin/php test.php

real 0m1.132s
user 0m1.118s
sys 0m0.015s

對的,我們用的就是字符串型的數(shù)字,從緩存拿出來就是這樣子的啦!所以這里是特意轉(zhuǎn)成字符串的(如果直接是數(shù)字,并不會出現(xiàn)這個問題 ,各位可以自行驗證)??梢钥闯鰰r間耗掉了1秒,才3000次循環(huán),后面的sys用時也注定我們用strace不會拿到什么有效信息。

shell$ strace -ttt -o xxx /usr/local/php/bin/php test.php
shell$ less xxx

如何解決php的in_array低性能問題

我們只看到這兩次系統(tǒng)調(diào)用之間的延時非常大,卻并不知道干了什么?一籌莫展了,幸好,Linux下的調(diào)試?yán)鞒藄trace還有l(wèi)trace(當(dāng)然還有dtrace,ptrace,不在本文討論范圍了,略去)。

引用:strace用來 跟蹤一個進程的系統(tǒng)調(diào)用或信號產(chǎn)生的情況,而 ltrace用來 跟蹤進程調(diào)用庫函數(shù)的情況(via IBM developerworks)。

為了排除干擾因素,我們將$x直接賦值為array(“0″,”1″,”2″,……)的形式,避免過多的malloc調(diào)用影響結(jié)果。執(zhí)行

shell$ ltrace -c /usr/local/php/bin/php test.php

如圖2

如何解決php的in_array低性能問題


我們看到庫函數(shù)__strtol_internal的調(diào)用非常之頻繁,達到了94%,太夸張了,然后我又查了一下這個庫函數(shù)__strtol_internal是干嘛的,原來是strtol的別名,簡單的說就是把字符串轉(zhuǎn)換成長整形,可以猜測PHP引擎已經(jīng)檢測到這是一個字符串型的數(shù)字,所以期望將他們轉(zhuǎn)換成長整型來比較,這個轉(zhuǎn)換過程中消耗了太多時間,我們再次執(zhí)行:

復(fù)制代碼 代碼如下:

shell$ ltrace -e "__strtol_internal" /usr/local/php/bin/php test.php 


可以輕松抓到大量下圖這樣的調(diào)用,到此,問題找到了,in_array這種松比較,會將兩個字符型數(shù)字串先轉(zhuǎn)換為長整型再進行比較,卻不知性能就耗在這上面了。

如何解決php的in_array低性能問題

知道了癥結(jié)所在,我們解決的辦法就很多了,最簡單的就是為in_array加第三個參數(shù)為true,即變?yōu)閲?yán)格比較,同時還要比較類型,這樣避免了PHP自作聰明的轉(zhuǎn)換類型,跑起來果然快多了,代碼如下:

復(fù)制代碼 代碼如下:

<?php
$y="1800";
$x = array();
for($j=0;$j<2000;$j++){
        $x[]= "{$j}";
}

for($i=0;$i<3000;$i++){
        if(in_array($y,$x,true)){
                continue;
        }
}
?>

復(fù)制代碼 代碼如下:

shell$ time /usr/local/php/bin/php test.php

real 0m0.267s
user 0m0.247s
sys 0m0.020s 


快了好多倍?。。?!可以看到sys耗時幾乎沒有太大變化。我們再次ltrace一把,還是要把$x直接賦值,排除malloc調(diào)用的干擾,因為我們實際應(yīng)用中是從緩存里一次拉出來的,所以也不存在示例代碼中這樣的循環(huán)來申請內(nèi)存的情況。
再次執(zhí)行

復(fù)制代碼 代碼如下:

shell$ ltrace -c /usr/local/php/bin/php test.php


如下圖:

如何解決php的in_array低性能問題

__ctype_tolower_loc占用了最多的時間!查了一下庫函數(shù)__ctype_tolower_loc是干嘛的:簡單的理解是將字符串轉(zhuǎn)換成小寫,那么這說明in_array比較字符串不區(qū)分大小寫嗎?其實這個函數(shù)調(diào)用已經(jīng)和我們這個in_array感覺聯(lián)系不大了,關(guān)于in_array的實現(xiàn),還是去看看PHP的源碼,大概理解的更為透徹了,好了,沒法往下說了,歡迎與我交流,寫的不對的地方請多多斧正。

———————2013.08.29分割線——————————

晚上又翻了以下PHP 5.4.10的源碼,對in_array的興趣真大啊,哈哈,位于./ext/standard/array.c的第1248行,可以看到他調(diào)用了php_search_array函數(shù),下面的array_serach也是調(diào)的這個,只是最后一個參數(shù)不同!經(jīng)過一番跟蹤,在in_array松比較的情況下,他最終調(diào)用的函數(shù) zendi_smart_strcmp(果然是個“聰明”函數(shù))進行比較,位于./Zend/zend_operators.c,我們用ltrace抓到的大量轉(zhuǎn)換成整型的操作就是那個is_numeric_string_ex的行為。

如何解決php的in_array低性能問題

函數(shù)is_numeric_string_ex是在./Zend/zend_operators.h中定義的,在前面進行了一堆的判斷和轉(zhuǎn)換之后,在232行調(diào)用了strtol,就是我們在文章中提到的系統(tǒng)函數(shù)了,將字符串轉(zhuǎn)換成長整型,有圖有真相

如何解決php的in_array低性能問題

到此,相信大家對“如何解決php的in_array低性能問題”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI