本篇內(nèi)容主要講解“如何解決php的in_array低性能問(wèn)題”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“如何解決php的in_array低性能問(wèn)題”吧!
創(chuàng)新互聯(lián)服務(wù)項(xiàng)目包括東蘭網(wǎng)站建設(shè)、東蘭網(wǎng)站制作、東蘭網(wǎng)頁(yè)制作以及東蘭網(wǎng)絡(luò)營(yíng)銷策劃等。多年來(lái),我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢(shì)、行業(yè)經(jīng)驗(yàn)、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,東蘭網(wǎng)站推廣取得了明顯的社會(huì)效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到東蘭省份的部分城市,未來(lái)相信會(huì)繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!PHP的性能一直在提高。然而,若是用的不恰當(dāng),或是一個(gè)不留神,還是可能會(huì)踩到PHP內(nèi)部實(shí)現(xiàn)方面的坑的。
復(fù)制代碼 代碼如下:
$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
對(duì)的,我們用的就是字符串型的數(shù)字,從緩存拿出來(lái)就是這樣子的啦!所以這里是特意轉(zhuǎn)成字符串的(如果直接是數(shù)字,并不會(huì)出現(xiàn)這個(gè)問(wèn)題 ,各位可以自行驗(yàn)證)??梢钥闯鰰r(shí)間耗掉了1秒,才3000次循環(huán),后面的sys用時(shí)也注定我們用strace不會(huì)拿到什么有效信息。
shell$ strace -ttt -o xxx /usr/local/php/bin/php test.php
shell$ less xxx
我們只看到這兩次系統(tǒng)調(diào)用之間的延時(shí)非常大,卻并不知道干了什么?一籌莫展了,幸好,Linux下的調(diào)試?yán)鞒藄trace還有l(wèi)trace(當(dāng)然還有dtrace,ptrace,不在本文討論范圍了,略去)。
引用:strace用來(lái) 跟蹤一個(gè)進(jìn)程的系統(tǒng)調(diào)用或信號(hào)產(chǎn)生的情況,而 ltrace用來(lái) 跟蹤進(jìn)程調(diào)用庫(kù)函數(shù)的情況(via IBM developerworks)。
為了排除干擾因素,我們將$x直接賦值為array(“0″,”1″,”2″,……)的形式,避免過(guò)多的malloc調(diào)用影響結(jié)果。執(zhí)行
shell$ ltrace -c /usr/local/php/bin/php test.php
如圖2
我們看到庫(kù)函數(shù)__strtol_internal的調(diào)用非常之頻繁,達(dá)到了94%,太夸張了,然后我又查了一下這個(gè)庫(kù)函數(shù)__strtol_internal是干嘛的,原來(lái)是strtol的別名,簡(jiǎn)單的說(shuō)就是把字符串轉(zhuǎn)換成長(zhǎng)整形,可以猜測(cè)PHP引擎已經(jīng)檢測(cè)到這是一個(gè)字符串型的數(shù)字,所以期望將他們轉(zhuǎn)換成長(zhǎng)整型來(lái)比較,這個(gè)轉(zhuǎn)換過(guò)程中消耗了太多時(shí)間,我們?cè)俅螆?zhí)行:
復(fù)制代碼 代碼如下:
shell$ ltrace -e "__strtol_internal" /usr/local/php/bin/php test.php
可以輕松抓到大量下圖這樣的調(diào)用,到此,問(wèn)題找到了,in_array這種松比較,會(huì)將兩個(gè)字符型數(shù)字串先轉(zhuǎn)換為長(zhǎng)整型再進(jìn)行比較,卻不知性能就耗在這上面了。
知道了癥結(jié)所在,我們解決的辦法就很多了,最簡(jiǎn)單的就是為in_array加第三個(gè)參數(shù)為true,即變?yōu)閲?yán)格比較,同時(shí)還要比較類型,這樣避免了PHP自作聰明的轉(zhuǎn)換類型,跑起來(lái)果然快多了,代碼如下:
復(fù)制代碼 代碼如下:
$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耗時(shí)幾乎沒(méi)有太大變化。我們?cè)俅蝜trace一把,還是要把$x直接賦值,排除malloc調(diào)用的干擾,因?yàn)槲覀儗?shí)際應(yīng)用中是從緩存里一次拉出來(lái)的,所以也不存在示例代碼中這樣的循環(huán)來(lái)申請(qǐng)內(nèi)存的情況。
再次執(zhí)行
復(fù)制代碼 代碼如下:
shell$ ltrace -c /usr/local/php/bin/php test.php
如下圖:
__ctype_tolower_loc占用了最多的時(shí)間!查了一下庫(kù)函數(shù)__ctype_tolower_loc是干嘛的:簡(jiǎn)單的理解是將字符串轉(zhuǎn)換成小寫(xiě),那么這說(shuō)明in_array比較字符串不區(qū)分大小寫(xiě)嗎?其實(shí)這個(gè)函數(shù)調(diào)用已經(jīng)和我們這個(gè)in_array感覺(jué)聯(lián)系不大了,關(guān)于in_array的實(shí)現(xiàn),還是去看看PHP的源碼,大概理解的更為透徹了,好了,沒(méi)法往下說(shuō)了,歡迎與我交流,寫(xiě)的不對(duì)的地方請(qǐng)多多斧正。
———————2013.08.29分割線——————————
晚上又翻了以下PHP 5.4.10的源碼,對(duì)in_array的興趣真大啊,哈哈,位于./ext/standard/array.c的第1248行,可以看到他調(diào)用了php_search_array函數(shù),下面的array_serach也是調(diào)的這個(gè),只是最后一個(gè)參數(shù)不同!經(jīng)過(guò)一番跟蹤,在in_array松比較的情況下,他最終調(diào)用的函數(shù) zendi_smart_strcmp(果然是個(gè)“聰明”函數(shù))進(jìn)行比較,位于./Zend/zend_operators.c,我們用ltrace抓到的大量轉(zhuǎn)換成整型的操作就是那個(gè)is_numeric_string_ex的行為。
函數(shù)is_numeric_string_ex是在./Zend/zend_operators.h中定義的,在前面進(jìn)行了一堆的判斷和轉(zhuǎn)換之后,在232行調(diào)用了strtol,就是我們?cè)谖恼轮刑岬降南到y(tǒng)函數(shù)了,將字符串轉(zhuǎn)換成長(zhǎng)整型,有圖有真相
到此,相信大家對(duì)“如何解決php的in_array低性能問(wèn)題”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)建站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!