遭遇php的in_array低效能問題_PHP教程

來源:互聯網
上載者:User
PHP的效能一直在提高。然而,若是用的不恰當,或是一個不留神,還是可能會踩到PHP內部實現方面的坑的。我在前幾天的一個效能問題上就碰到了。

事情是這樣子的,一位同事反饋我們的一個介面每次返回需要5秒之久,我們一起review了代碼,“驚喜”的發現居然在迴圈(大約900次)中調用了一個讀緩衝的操作,而這個緩衝的key並沒有改變,因此我們把這段代碼移到了迴圈外面,再測,介面返回時間降到了2秒,嗚呼!雖然提升了1倍,但明顯不是我們能接受的結果!
出現效能問題的代碼量並不大,我們排除了IO問題以後,寫了一段測試代碼,果然問題很快重現。

複製代碼 代碼如下:
$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

對的,我們用的就是字串型的數字,從緩衝拿出來就是這樣子的啦!所以這裡是特意轉成字串的(如果直接是數字,並不會出現這個問題 ,各位可以自行驗證)。可以看出時間耗掉了1秒,才3000次迴圈,後面的sys用時也註定我們用strace不會拿到什麼有效資訊。

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



我們只看到這兩次系統調用之間的延時非常大,卻並不知道幹了什嗎?一籌莫展了,幸好,Linux下的調試利器除了strace還有ltrace(當然還有dtrace,ptrace,不在本文討論範圍了,略去)。

引用:strace用來 跟蹤一個進程的系統調用或訊號產生的情況,而 ltrace用來 跟蹤進程調用庫函數的情況(via IBM developerworks)。

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

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

2




我們看到庫函數__strtol_internal的調用非常之頻繁,達到了94%,太誇張了,然後我又查了一下這個庫函數__strtol_internal是幹嘛的,原來是strtol的別名,簡單的說就是把字串轉換成長整形,可以猜測PHP引擎已經檢測到這是一個字串型的數字,所以期望將他們轉換成長整型來比較,這個轉換過程中消耗了太多時間,我們再次執行:

複製代碼 代碼如下:
shell$ ltrace -e "__strtol_internal" /usr/local/php/bin/php test.php


可以輕鬆抓到大量這樣的調用,到此,問題找到了,in_array這種松比較,會將兩個字元型數字串先轉換為長整型再進行比較,卻不知效能就耗在這上面了。



知道了癥結所在,我們解決的辦法就很多了,最簡單的就是為in_array加第三個參數為true,即變為嚴格比較,同時還要比較類型,這樣避免了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;
}
}
?>

複製代碼 代碼如下:
shell$ time /usr/local/php/bin/php test.php

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


快了好多倍啊!!!可以看到sys耗時幾乎沒有太大變化。我們再次ltrace一把,還是要把$x直接賦值,排除malloc調用的幹擾,因為我們實際應用中是從緩衝裡一次拉出來的,所以也不存在範例程式碼中這樣的迴圈來申請記憶體的情況。
再次執行

複製代碼 代碼如下:
shell$ ltrace -c /usr/local/php/bin/php test.php


如:

__ctype_tolower_loc佔用了最多的時間!查了一下庫函數__ctype_tolower_loc是幹嘛的:簡單的理解是將字串轉換成小寫,那麼這說明in_array比較字串不區分大小寫嗎?其實這個函數調用已經和我們這個in_array感覺聯絡不大了,關於in_array的實現,還是去看看PHP的源碼,大概理解的更為透徹了,好了,沒法往下說了,歡迎與我交流,寫的不對的地方請多多斧正。

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

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



函數is_numeric_string_ex是在./Zend/zend_operators.h中定義的,在前面進行了一堆的判斷和轉換之後,在232行調用了strtol,就是我們在文章中提到的系統函數了,將字串轉換成長整型,有圖有真相

http://www.bkjia.com/PHPjc/313618.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/313618.htmlTechArticlePHP的效能一直在提高。然而,若是用的不恰當,或是一個不留神,還是可能會踩到PHP內部實現方面的坑的。我在前幾天的一個效能問題上就...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.