精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

PHP 性能分析與實驗:性能的微觀分析

開發 后端
,我們從 PHP 是解釋性語言、動態語言和底層實現等三個方面,探討了 PHP 性能的問題。本文就深入到 PHP 的微觀層面,我們來了解 PHP 在使用和編寫代碼過程中,性能方面,可能需要注意和提升的地方。

上一篇文章中,我們從 PHP 是解釋性語言、動態語言和底層實現等三個方面,探討了 PHP 性能的問題。本文就深入到 PHP 的微觀層面,我們來了解 PHP 在使用和編寫代碼過程中,性能方面,可能需要注意和提升的地方。

在開始分析之前,我們得掌握一些與性能分析相關的函數。這些函數讓我們對程序性能有更好的分析和評測。

[[148876]]

一、性能分析相關的函數與命令

1.1、時間度量函數

平時我們常用 time() 函數,但是返回的是秒數,對于某段代碼的內部性能分析,到秒的精度是不夠的。于是要用 microtime 函數。而 microtime 函數可以返回兩種形式,一是字符串的形式,一是浮點數的形式。不過需要注意的是,在缺省的情況下,返回的精度只有4位小數。為了獲得更高的精確度,我們需要配置 precision。

如下是 microtime 的使用結果。

  1. $start= microtime(true); 
  2. echo $start."/n"
  3. $end = microtime(true); 
  4. echo $end."/n"
  5. echo ($end-$start)."/n"

輸出為:

 

  1. bash-3.2# phptime.php 
  2.  
  3. 1441360050.3286  
  4. 1441360050.3292  
  5. 0.00053000450134277 

而在代碼前面加上一行:

  1. ini_set("precision"16); 

輸出為:

 

  1. bash-3.2# phptime.php 
  2. 1441360210.932628  
  3. 1441360210.932831  
  4. 0.0002031326293945312 

除了 microtime 內部統計之外, 還可以使用 getrusage 來取得用戶態的時長。在實際的操作中,也常用 time 命令來計算整個程序的運行時長,通過多次運行或者修改代碼后運行,得到不同的時間長度以得到效率上的區別。 具體用法是:time phptime.php ,則在程序運行完成之后,不管是否正常結束退出,都會有相關的統計。

 

  1. bash-3.2# time phptime.php 
  2. 1441360373.150756  
  3. 1441360373.150959  
  4. 0.0002031326293945312 
  5. real 0m0.186s  
  6. user 0m0.072s  
  7. sys 0m0.077s 

因為本文所討論的性能問題,往往分析上百萬次調用之后的差距與趨勢,為了避免代碼中存在一些時間統計代碼,后面我們使用 time 命令居多。

1.2、內存使用相關函數

分析內存使用的函數有兩個:memory_ get_ usage、memory_ get_ peak_usage,前者可以獲得程序在調用的時間點,即當前所使用的內存,后者可以獲得到目前為止高峰時期所使用的內存。所使用的內存以字節為單位。

 

  1. $base_memory= memory_get_usage(); 
  2. echo "Hello,world!/n"
  3. $end_memory= memory_get_usage(); 
  4. $peak_memory= memory_get_peak_usage(); 
  5. echo $base_memory,"/t",$end_memory,"/t",($end_memory-$base_memory),"/t", $peak_memory,"/n"

輸出如下:

 

  1. bash-3.2# phphelloworld.php 
  2. Hello,world!  
  3. 224400 224568 168 227424 

可以看到,即使程序中間只輸出了一句話,再加上變量存儲,也消耗了168個字節的內存。

對于同一程序,不同 PHP 版本對內存的使用并不相同,甚至還差別很大。

 

  1. $baseMemory= memory_get_usage(); 
  2. class User 
  3. private $uid; 
  4. function __construct($uid) 
  5.     { 
  6. $this->uid= $uid; 
  7.     } 
  8.  
  9. for($i=0;$i<100000;$i++) 
  10. $obj= new User($i); 
  11. if ( $i% 10000 === 0 ) 
  12.     { 
  13. echo sprintf( '%6d: ', $i), memory_get_usage(), " bytes/n"
  14.     } 
  15. echo "  peak: ",memory_get_peak_usage(true), " bytes/n"

在 PHP 5.2 中,內存使用如下:

 

  1. [root@localhostphpperf]# php52 memory.php 
  2.  
  3. 093784 bytes  
  4. 1000093784 bytes  
  5. …… 8000093784 bytes  
  6. 9000093784 bytes  
  7. peak: 262144 bytes 

PHP 5.3 中,內存使用如下

 

  1. [root@localhostphpperf]# phpmemory.php 
  2.  
  3. 0634992 bytes  
  4. 10000634992 bytes  
  5. …… 80000634992 bytes  
  6. 90000634992 bytes  
  7. peak: 786432 bytes 

可見 PHP 5.3 在內存使用上要粗放了一些。

PHP 5.4 – 5.6 差不多,有所優化:

 

  1. [root@localhostphpperf]# php56 memory.php 
  2.  
  3. 0224944 bytes  
  4. 10000224920 bytes  
  5. …… 80000224920 bytes  
  6. 90000224920 bytes  
  7. peak: 262144 bytes 

而 PHP 7 在少量使用時,高峰內存的使用,增大很多。

 

  1. [root@localhostphpperf]# php7 memory.php 
  2.  
  3. 0: 353912 bytes  
  4. 10000: 353912 bytes  
  5. …… 80000: 353912 bytes  
  6. 90000: 353912 bytes  
  7. peak: 2097152 bytes 

從上面也看到,以上所使用的 PHP 都有比較好的垃圾回收機制,10萬次初始化,并沒有隨著對象初始化的增多而增加內存的使用。PHP7 的高峰內存使用最多,達到了接近 2M。

下面再來看一個例子,在上面的代碼的基礎上,我們加上一行,如下:

$obj->self = $obj;

代碼如下:

  1. $baseMemory= memory_get_usage(); 
  2. class User 
  3. private $uid
  4. function __construct($uid
  5.     { 
  6. $this->uid= $uid
  7.     } 
  8.  
  9. for($i=0;$i<100000;$i++) 
  10. $objnew User($i); 
  11. $obj->self = $obj
  12. if ( $i% 5000 === 0 ) 
  13.     { 
  14. echo sprintf( '%6d: '$i), memory_get_usage(), " bytes/n"
  15.     } 
  16. echo "  peak: ",memory_get_peak_usage(true), " bytes/n"

這時候再來看看內存的使用情況,中間表格主體部分為內存使用量,單位為字節。

PHP 性能分析與實驗:性能的微觀分析

圖表如下:

PHP 性能分析與實驗:性能的微觀分析

PHP 5.2 并沒有合適的垃圾回收機制,導致內存使用越來越多。而5.3 以后內存回收機制導致內存穩定在一個區間。而也可以看見 PHP7 內存使用最少。把 PHP 5.2 的圖形去掉了之后,對比更為明顯。

PHP 性能分析與實驗:性能的微觀分析

可見 PHP7 不僅是在算法效率上,有大幅度的提升,在大批量內存使用上也有大幅度的優化(盡管小程序的高峰內存比歷史版本所用內存更多)。

1.3、垃圾回收相關函數

在 PHP 中,內存回收是可以控制的,我們可以顯式地關閉或者打開垃圾回收,一種方法是通過修改配置,zend.enable_gc=Off 就可以關掉垃圾回收。 缺省情況下是 On 的。另外一種手段是通過 gc _enable()和gc _disable()函數分別打開和關閉垃圾回收。

比如在上面的例子的基礎上,我們關閉垃圾回收,就可以得到如下數據表格和圖表。

代碼如下:

 

  1. gc_disable(); 
  2. $baseMemory= memory_get_usage(); 
  3. class User 
  4. private $uid
  5. function __construct($uid
  6.     { 
  7. $this->uid= $uid
  8.     } 
  9.  
  10. for($i=0;$i<100000;$i++) 
  11. $objnew User($i); 
  12. $obj->self = $obj
  13. if ( $i% 5000 === 0 ) 
  14.     { 
  15. echo sprintf( '%6d: '$i), memory_get_usage(), " bytes/n"
  16.     } 
  17. echo "  peak: ",memory_get_peak_usage(true), " bytes/n"

分別在 PHP 5.3、PHP5.4 、PHP5.5、PHP5.6 、PHP7 下運行,得到如下內存使用統計表。

PHP 性能分析與實驗:性能的微觀分析

圖表如下,PHP7 還是內存使用效率最優的。

PHP 性能分析與實驗:性能的微觀分析

從上面的例子也可以看出來,盡管在第一個例子中,PHP7 的高峰內存使用數是最多的,但是當內存使用得多時,PHP7 的內存優化就體現出來了。

這里值得一提的是垃圾回收,盡管會使內存減少,但是會導致速度降低,因為垃圾回收也是需要消耗 CPU 等其他系統資源的。Composer 項目就曾經因為在計算依賴前關閉垃圾回收,帶來成倍性能提升,引發廣大網友關注。詳見:

https://github.com/composer/composer/commit/ac676f47f7bbc619678a29deae097b6b0710b799

在常見的代碼和性能分析中,出了以上三類函數之外,還常使用的有堆棧跟蹤函數、輸出函數,這里不再贅述。

#p#

二、PHP 性能分析10則

下面我們根據小程序來驗證一些常見的性能差別。

2.1、使用 echo 還是 print

在有的建議規則中,會建議使用 echo ,而不使用 print。說 print 是函數,而 echo 是語法結構。實際上并不是如此,print 也是語法結構,類似的語法結構,還有多個,比如 list、isset、require 等。不過對于 PHP 7 以下 PHP 版本而言,兩者確實有性能上的差別。如下兩份代碼:

  1. for($i=0; $i<1000000; $i++) 
  2. echo("Hello,World!"); 
  3. for($i=0; $i<1000000; $i++) 
  4. print ("Hello,World!"); 

在 PHP 5.3 中運行速度分別如下(各2次):

  1. [root@localhostphpperf]# time php echo1.php > /dev/null 
  2. real 0m0.233s 
  3. user 0m0.153s 
  4. sys 0m0.080s 
  5. [root@localhostphpperf]# time php echo1.php > /dev/null 
  6. real 0m0.234s 
  7. user 0m0.159s 
  8. sys 0m0.073s 
  9. [root@localhostphpperf]# time phpecho.php> /dev/null 
  10. real 0m0.203s 
  11. user 0m0.130s 
  12. sys 0m0.072s 
  13. [root@localhostphpperf]# time phpecho.php> /dev/null 
  14. real 0m0.203s 
  15. user 0m0.128s 
  16. sys 0m0.075s 

在 PHP5.3 版中效率差距10%以上。而在 PHP5.4 以上的版本中,區別不大,如下是 PHP7 中的運行效率。

  1. [root@localhostphpperf]# time php7 echo.php> /dev/null 
  2. real 0m0.151s 
  3. user 0m0.088s 
  4. sys 0m0.062s 
  5. [root@localhostphpperf]# time php7 echo.php> /dev/null 
  6. real 0m0.145s 
  7. user 0m0.084s 
  8. sys 0m0.061s 
  9. [root@localhostphpperf]# time php7 echo1.php > /dev/null 
  10. real 0m0.140s 
  11. user 0m0.075s 
  12. sys 0m0.064s 
  13. [root@localhostphpperf]# time php7 echo1.php > /dev/null 
  14. real 0m0.146s 
  15. user 0m0.077s 
  16. sys 0m0.069s 

正如瀏覽器前端的一些優化準則一樣,沒有啥特別通用的原則,往往根據不同的情況和版本,規則也會存在不同。

2.2、require 還是 require_once?

在一些常規的優化規則中,會提到,建議使用 require_ once 而不是 require,現由是 require_ once 會去檢測是否重復,而 require 則不需要重復檢測。

在大量不同文件的包含中,require_ once 略慢于 require。但是 require_ once 的檢測是一項內存中的行為,也就是說即使有數個需要加載的文件,檢測也只是內存中的比較。而 require 的每次重新加載,都會從文件系統中去讀取分析。因而 require_ once 會比 require 更佳。咱們也使用一個例子來看一下。

  1. str.php 
  2. global$str
  3. $str"China has a large population"
  4. require.php 
  5. for($i=0; $i<100000; $i++) { 
  6. require "str.php"
  7. require_once.php 
  8. for($i=0; $i<100000; $i++) { 
  9. require_once"str.php"

上面的例子,在 PHP7 中,require_ once.php 的運行速度是 require.php 的30倍!在其他版本也能得到大致相同的結果。

  1. [root@localhostphpperf]# time php7 require.php 
  2. real 0m1.712s 
  3. user 0m1.126s 
  4. sys 0m0.569s 
  5. [root@localhostphpperf]# time php7 require.php 
  6. real 0m1.640s 
  7. user 0m1.113s 
  8. sys 0m0.515s 
  9. [root@localhostphpperf]# time php7 require_once.php 
  10. real 0m0.066s 
  11. user 0m0.063s 
  12. sys 0m0.003s 
  13. [root@localhostphpperf]# time php7 require_once.php 
  14. real 0m0.057s 
  15. user 0m0.052s 
  16. sys 0m0.004s 

從上可以看到,如果存在大量的重復加載的話,require_ once 明顯優于 require,因為重復的文件不再有 IO 操作。即使不是大量重復的加載,也建議使用 require_ once,因為在一個程序中,一般不會存在數以千百計的文件包含,100次內存比較的速度差距,一個文件包含就相當了。

2.3、單引號還是雙引號?

單引號,還是雙引號,是一個問題。一般的建議是能使用單引號的地方,就不要使用雙引號,因為字符串中的單引號,不會引起解析,從而效率更高。那來看一下實際的差別。

  1. classUser 
  2. private $uid
  3. private $username
  4. private $age
  5. function  __construct($uid$username,$age){ 
  6. $this->uid= $uid
  7. $this->username = $username
  8. $this->age = $age
  9.     } 
  10. function getUserInfo() 
  11.     { 
  12. return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age; 
  13.     } 
  14. function getUserInfoSingle() 
  15.     { 
  16. return 'UID:'.$this->uid.' UserName:'.$this->username.' Age'.$this->age; 
  17.     } 
  18. function getUserInfoOnce() 
  19.     { 
  20. return "UID:{$this->uid}UserName:{$this->username} Age:{$this->age}"
  21.     } 
  22. function getUserInfoSingle2() 
  23.     { 
  24. return 'UID:{$this->uid} UserName:{$this->username} Age:{$this->age}'
  25.     } 
  26. for($i=0; $i<1000000;$i++) { 
  27. $user = new User($i"name".$i$i%100); 
  28. $user->getUserInfoSingle(); 

在上面的 User 類中,有四個不同的方法,完成一樣的功能,就是拼接信息返回,看看這四個不同的方法的區別。

第一個、getUserInfo ,使用雙引號和屬性相拼接

  1. [root@localhostphpperf]# time php7 string.php 
  2. real 0m0.670s 
  3. user 0m0.665s 
  4. sys 0m0.002s 
  5. [root@localhostphpperf]# time php7 string.php 
  6. real 0m0.692s 
  7. user 0m0.689s 
  8. sys 0m0.002s 
  9. [root@localhostphpperf]# time php7 string.php 
  10. real 0m0.683s 
  11. user 0m0.672s 
  12. sys 0m0.004s 

第二個、getUserInfoSingle ,使用單引號和屬性相拼接

  1. [root@localhostphpperf]# time php7 string.php 
  2. real 0m0.686s 
  3. user 0m0.683s 
  4. sys 0m0.001s 
  5. [root@localhostphpperf]# time php7 string.php 
  6. real 0m0.671s 
  7. user 0m0.666s 
  8. sys 0m0.003s 
  9. [root@localhostphpperf]# time php7 string.php 
  10. real 0m0.669s 
  11. user 0m0.666s 
  12. sys 0m0.002s 

可見在拼接中,單雙引號并無明顯差別。

第三個、getUserInfoOnce,不再使用句號.連接,而是直接引入在字符串中解析。

  1. [root@localhostphpperf]# time php7 string.php 
  2. real 0m0.564s 
  3. user 0m0.556s 
  4. sys 0m0.006s 
  5. [root@localhostphpperf]# time php7 string.php 
  6. real 0m0.592s 
  7. user 0m0.587s 
  8. sys 0m0.004s 
  9. [root@localhostphpperf]# time php7 string.php 
  10. real 0m0.563s 
  11. user 0m0.559s 
  12. sys 0m0.003s 

從上面可見,速度提高了0.06s-0.10s,有10%-20%的效率提升。可見連綴效率更低一些。

第四個、getUserInfoSingle2 雖然沒有達到我們真正想要的效果,功能是不正確的,但是在字符串中,不再需要解析變量和獲取變量值,所以效率確實有大幅度提升。

  1. [root@localhostphpperf]# time php7 string.php 
  2. real 0m0.379s 
  3. user 0m0.375s 
  4. sys 0m0.003s 
  5. [root@localhostphpperf]# time php7 string.php 
  6. real 0m0.399s 
  7. user 0m0.394s 
  8. sys 0m0.003s 
  9. [root@localhostphpperf]# time php7 string.php 
  10. real 0m0.377s 
  11. user 0m0.371s 
  12. sys 0m0.004s 

效率確實有了大的提升,快了50%。

那么這個快,是由于不需要變量引用解析帶來的,還是只要加入$天然的呢?我們再試著寫了一個方法。

  1. functiongetUserInfoSingle3() 
  2. return "UID:{\$this->uid} UserName:{\$this->username} Age:{\$this->age}"

得到如下運行時間:

  1. [root@localhostphpperf]# time php7 string.php 
  2. real 0m0.385s 
  3. user 0m0.381s 
  4. sys 0m0.002s 
  5. [root@localhostphpperf]# time php7 string.php 
  6. real 0m0.382s 
  7. user 0m0.380s 
  8. sys 0m0.002s 
  9. [root@localhostphpperf]# time php7 string.php 
  10. real 0m0.386s 
  11. user 0m0.380s 
  12. sys 0m0.004s 

發現轉義后的字符串,效率跟單引號是一致的,從這里也可以看見,單引號還是雙引號包含,如果不存在需要解析的變量,幾乎沒有差別。如果有需要解析的變量,你也不能光用單引號,要么使用單引號和連綴,要么使用內部插值,所以在這條規則上,不用太過糾結。

2.4、錯誤應該打開還是關閉?

在 PHP 中,有多種錯誤消息,錯誤消息的開啟是否會帶來性能上的影響呢?從直覺覺得,由于錯誤消息,本身會涉及到 IO 輸出,無論是輸出到終端或者 error_log,都是如此,所以肯定會影響性能。我們來看看這個影響有多大。

error_reporting(E_ERROR);
for($i=0; $i<1000000;$i++) {
$str= "通常,$PHP中的垃圾回收機制,僅僅在循環回收算法確實運行時會有時間消耗上的增加。但是在平常的(更小的)腳本中應根本就沒有性能影響。
然而,在平常腳本中有循環回收機制運行的情況下,內存的節省將允許更多這種腳本同時運行在你的服務器上。因為總共使用的內存沒達到上限。";
}

在上面的代碼中,我們涉及到一個不存在的變量,所以會報出 Notice 錯誤:

Notice: Undefined variable: PHP 中的垃圾回收機制,僅僅在循環回收算法確實運行時會有時間消耗上的增加。但是在平常的 in xxxx/string2.php on line 10

如果把 E_ ERROR 改成 E_ ALL 就能看到大量的上述錯誤輸出。

我們先執行 E_ ERROR 版,這個時候沒有任何錯誤日志輸出。得到如下數據:

  1. [root@localhostphpperf]# time php7 string2.php 
  2. real 0m0.442s 
  3. user 0m0.434s 
  4. sys 0m0.005s 
  5. [root@localhostphpperf]# time php7 string2.php 
  6. real 0m0.487s 
  7. user 0m0.484s 
  8. sys 0m0.002s 
  9. [root@localhostphpperf]# time php7 string2.php 
  10. real 0m0.476s 
  11. user 0m0.471s 
  12. sys 0m0.003s 

再執行 E_ ALL 版,有大量的錯誤日志輸出,我們把輸出重定向到/dev/null

  1. [root@localhostphpperf]# time php7 string2.php > /dev/null 
  2. real 0m0.928s 
  3. user 0m0.873s 
  4. sys 0m0.051s 
  5. [root@localhostphpperf]# time php7 string2.php > /dev/null 
  6. real 0m0.984s 
  7. user 0m0.917s 
  8. sys 0m0.064s 
  9. [root@localhostphpperf]# time php7 string2.php > /dev/null 
  10. real 0m0.945s 
  11. user 0m0.887s 
  12. sys 0m0.056s 

可見慢了將近一倍。

如上可見,即使輸出沒有正式寫入文件,錯誤級別打開的影響也是巨大的。在線上我們應該將錯誤級別調到 E_ ERROR 這個級別,同時將錯誤寫入 error_ log,既減少了不必要的錯誤信息輸出,又避免泄漏路徑等信息,造成安全隱患。

2.5、正則表達式和普通字符串操作

在字符串操作中,有一條常見的規則,即是能使用普通字符串操作方法替代的,就不要使用正則表達式來處理,用 C 語言操作 PCRE 做過正則表達式處理的童鞋應該清楚,需要先 compile,再 exec,也就是說是一個相對復雜的過程。現在就比較一下兩者的差別。

對于簡單的分隔,我們可以使用 explode 來實現,也可以使用正則表達式,比如下面的例子:

  1. ini_set("precision", 16); 
  2. function microtime_ex() 
  3. list($usec$sec) = explode(" ", microtime()); 
  4. return $sec+$usec
  5. for($i=0; $i<1000000; $i++) { 
  6. microtime_ex(); 

耗時在0.93-1S之間。

  1. [root@localhostphpperf]# time php7 pregstring.php 
  2. real 0m0.941s 
  3. user 0m0.931s 
  4. sys 0m0.007s 
  5. [root@localhostphpperf]# time php7 pregstring.php 
  6. real 0m0.986s 
  7. user 0m0.980s 
  8. sys 0m0.004s 
  9. [root@localhostphpperf]# time php7 pregstring.php 
  10. real 0m1.004s 
  11. user 0m0.998s 
  12. sys 0m0.003s 

我們再將分隔語句替換成:

  1. list($usec, $sec) = preg_split("#\s#", microtime()); 

得到如下數據,慢了近10-20%。

  1. [root@localhostphpperf]# time php7 pregstring1.php 
  2. real 0m1.195s 
  3. user 0m1.182s 
  4. sys 0m0.004s 
  5. [root@localhostphpperf]# time php7 pregstring1.php 
  6. real 0m1.222s 
  7. user 0m1.217s 
  8. sys 0m0.003s 
  9. [root@localhostphpperf]# time php7 pregstring1.php 
  10. real 0m1.101s 
  11. user 0m1.091s 
  12. sys 0m0.005s 

再將語句替換成:

list($usec, $sec) = preg_split("#\s+#", microtime());

即匹配一到多個空格,并沒有太多的影響。除了分隔外,查找我們也來看一個例子。

第一段代碼:

  1. $str= "China has a Large population"
  2. for($i=0; $i<1000000; $i++) { 
  3. if(preg_match("#l#i", $str)) 
  4.     { 
  5.     } 

第二段代碼:

  1. $str= "China has a large population"
  2. for($i=0; $i<1000000; $i++) { 
  3. if(stripos($str, "l")!==false
  4.     { 
  5.     } 

這兩段代碼達到的效果相同,都是查找字符串中有無 l 或者 L 字符。

在 PHP 7 下運行效果如下:

  1. [root@localhostphpperf]# time php7 pregstring2.php 
  2. real 0m0.172s 
  3. user 0m0.167s 
  4. sys 0m0.003s 
  5. [root@localhostphpperf]# time php7 pregstring2.php 
  6. real 0m0.199s 
  7. user 0m0.196s 
  8. sys 0m0.002s 
  9. [root@localhostphpperf]# time php7 pregstring3.php 
  10. real 0m0.185s 
  11. user 0m0.182s 
  12. sys 0m0.003s 
  13. [root@localhostphpperf]# time php7 pregstring3.php 
  14. real 0m0.184s 
  15. user 0m0.181s 
  16. sys 0m0.003s 

兩者區別不大。再看看在 PHP5.6 中的表現。

  1. [root@localhostphpperf]# time php56 pregstring2.php 
  2. real 0m0.470s 
  3. user 0m0.456s 
  4. sys 0m0.004s 
  5. [root@localhostphpperf]# time php56 pregstring2.php 
  6. real 0m0.506s 
  7. user 0m0.500s 
  8. sys 0m0.005s 
  9. [root@localhostphpperf]# time php56 pregstring3.php 
  10. real 0m0.348s 
  11. user 0m0.342s 
  12. sys 0m0.004s 
  13. [root@localhostphpperf]# time php56 pregstring3.php 
  14. real 0m0.376s 
  15. user 0m0.364s 
  16. sys 0m0.003s 

可見在 PHP 5.6 中表現還是非常明顯的,使用正則表達式慢了20%。PHP7 難道是對已使用過的正則表達式做了緩存?我們調整一下代碼如下:

  1. $str= "China has a Large population"
  2. for($i=0; $i<1000000; $i++) { 
  3. $pattern = "#".chr(ord('a')+$i%26)."#i"
  4. if($ret = preg_match($pattern, $str)!==false
  5.     { 
  6.     } 

這是一個動態編譯的 pattern。

  1. $str= "China has a large population"
  2. for($i=0; $i<1000000; $i++) { 
  3. $pattern = "".chr(ord('a')+$i%26).""
  4. if($ret = stripos($str, $pattern)!==false
  5.     { 
  6.     } 

在 PHP7 中,得到了如下結果:

  1. [root@localhostphpperf]# time php7 pregstring2.php 
  2. real 0m0.351s 
  3. user 0m0.346s 
  4. sys 0m0.004s 
  5. [root@localhostphpperf]# time php7 pregstring2.php 
  6. real 0m0.359s 
  7. user 0m0.352s 
  8. sys 0m0.004s 
  9. [root@localhostphpperf]# time php7 pregstring3.php 
  10. real 0m0.375s 
  11. user 0m0.369s 
  12. sys 0m0.003s 
  13. [root@localhostphpperf]# time php7 pregstring3.php 
  14. real 0m0.370s 
  15. user 0m0.365s 
  16. sys 0m0.005s 

可見兩者并不明顯。而在 PHP 5.6 中,同樣的代碼:

  1. [root@localhostphpperf]# time php56 pregstring2.php 
  2. real 0m1.022s 
  3. user 0m1.015s 
  4. sys 0m0.005s 
  5. [root@localhostphpperf]# time php56 pregstring2.php 
  6. real 0m1.049s 
  7. user 0m1.041s 
  8. sys 0m0.005s 
  9. [root@localhostphpperf]# time php56 pregstring3.php 
  10. real 0m0.923s 
  11. user 0m0.821s 
  12. sys 0m0.002s 
  13. [root@localhostphpperf]# time php56 pregstring3.php 
  14. real 0m0.838s 
  15. user 0m0.831s 
  16. sys 0m0.004s 

在 PHP 5.6 中,stripos 版明顯要快于正則表達式版,由上兩例可見,PHP7對正則表達式的優化還是相當驚人的。其次也建議,能用普通字符串操作的地方,可以避免使用正則表達式。 因為在其他版本中,這個規則還是適用的。某 zend 大牛官方的分享給出如下數據:

  • stripos(‘http://’, $website) 速度是preg_match(‘/http:\/\//i’, $website) 的兩倍

  • ctype_alnum()速度是preg_match(‘/^\s*$/’)的5倍;

  • “if ($test == (int)$test)” 比 preg_match(‘/^\d*$/’)快5倍

可以相見,正則表達式是相對低效的。

2.6、數組元素定位查找

在數組元素的查找中,有一個關鍵的注意點就是數組值和鍵的查找速度,差異非常大。了解過 PHP 擴展開發的朋友,應該清楚,數組在底層其實是 Hash 表。所以鍵是以快速定位的,而值卻未必。下面來看例子。

首先們構造一個數組:

$a= array();
for($i=0;$i<100000;$i++){
$a[$i] = $i;
}

在這個數組中,我們測試查找值和查找鍵的效率差別。

第一種方法用 array_ search,第二種用 array_ key_ exists,第三種用 isset 語法結構。 代碼分別如下:

//查找值
foreach($a as $i)
{
array_search($i, $a);
}
//查找鍵
foreach($a as $i)
{
array_key_exists($i, $a);
}
//判定鍵是否存在
foreach($a as $i)
{
if(isset($a[$i]));
}

運行結果如下:

[root@localhostphpperf]# time php7 array.php
real 0m9.026s
user 0m8.965s
sys 0m0.007s
[root@localhostphpperf]# time php7 array.php
real 0m9.063s
user 0m8.965s
sys 0m0.005s
[root@localhostphpperf]# time php7 array1.php
real 0m0.018s
user 0m0.016s
sys 0m0.001s
[root@localhostphpperf]# time php7 array1.php
real 0m0.021s
user 0m0.015s
sys 0m0.004s
[root@localhostphpperf]# time php7 array2.php
real 0m0.020s
user 0m0.014s
sys 0m0.006s
[root@localhostphpperf]# time php7 array2.php
real 0m0.016s
user 0m0.009s
sys 0m0.006s

由上例子可見,鍵值查找的速度比值查找的速度有百倍以上的效率差別。因而如果能用鍵值定位的地方,盡量用鍵值定位,而不是值查找。

2.7、對象與數組

在 PHP 中,數組就是字典,字典可以存儲屬性和屬性值,而且無論是鍵還是值,都不要求數據類型統一,所以對象數據存儲,既能用對象數據結構的屬性存儲數據,也能使用數組的元素存儲數據。那么兩者有何差別呢?

使用對象:

classUser
{
public $uid;
public $username;
public $age;
function getUserInfo()
    {
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
    }
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}

使用數組:

functiongetUserInfo($user)
{
return "UID:".$user['uid']." UserName:".$user['username']." Age:".$user['age'];
}
for($i=0; $i<1000000;$i++) {
$user = array("uid"=>$i,"age" =>$i%100,"username"=>"User".$i);
getUserInfo($user);
}

我們分別在 PHP5.3、PHP 5.6 和 PHP 7 中運行這兩段代碼。

[root@localhostphpperf]# time phpobject.php
real 0m2.144s
user 0m2.119s
sys 0m0.009s
[root@localhostphpperf]# time phpobject.php
real 0m2.106s
user 0m2.089s
sys 0m0.013s
[root@localhostphpperf]# time php object1.php
real 0m1.421s
user 0m1.402s
sys 0m0.016s
[root@localhostphpperf]# time php object1.php
real 0m1.431s
user 0m1.410s
sys 0m0.012s

在 PHP 5.3 中,數組版比對象版快了近30%。

[root@localhostphpperf]# time php56 object.php
real 0m1.323s
user 0m1.319s
sys 0m0.002s
[root@localhostphpperf]# time php56 object.php
real 0m1.414s
user 0m1.400s
sys 0m0.006s
[root@localhostphpperf]# time php56 object1.php
real 0m1.356s
user 0m1.352s
sys 0m0.002s
[root@localhostphpperf]# time php56 object1.php
real 0m1.364s
user 0m1.349s
sys 0m0.006s
[root@localhostphpperf]# time php7 object.php
real 0m0.642s
user 0m0.638s
sys 0m0.003s
[root@localhostphpperf]# time php7 object.php
real 0m0.606s
user 0m0.602s
sys 0m0.003s
[root@localhostphpperf]# time php7 object1.php
real 0m0.615s
user 0m0.613s
sys 0m0.000s
[root@localhostphpperf]# time php7 object1.php
real 0m0.615s
user 0m0.611s
sys 0m0.003s

到了 PHP 5.6 和 PHP7 中,兩個版本基本沒有差別,而在 PHP7 中的速度是 PHP5.6 中的2倍。在新的版本中,差別已幾乎沒有,那么為了清楚起見我們當然應該聲明類,實例化類來存儲對象數據。

2.8、getter 和 setter

從 Java 轉過來學習 PHP 的朋友,在對象聲明時,可能習慣使用 getter 和 setter,那么,在 PHP 中,使用 getter 和 setter 是否會帶來性能上的損失呢?同樣,先上例子。

無 setter版:

classUser
{
public $uid;
public $username;
public $age;
function getUserInfo()
    {
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
    }
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}

有 setter版:

classUser
{
public $uid;
private $username;
public $age;
function setUserName($name)
    {
$this->username = $name;
    }
function getUserInfo()
    {
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
    }
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->setUserName("User".$i);
$user->getUserInfo();
}

這里只增加了一個 setter。運行結果如下:

[root@localhostphpperf]# time php7 object.php
real 0m0.607s
user 0m0.602s
sys 0m0.004s
[root@localhostphpperf]# time php7 object.php
real 0m0.598s
user 0m0.596s
sys 0m0.000s
[root@localhostphpperf]# time php7 object2.php
real 0m0.673s
user 0m0.669s
sys 0m0.003s
[root@localhostphpperf]# time php7 object2.php
real 0m0.668s
user 0m0.664s
sys 0m0.004s

從上面可以看到,增加了一個 setter,帶來了近10%的效率損失。可見這個性能損失是相當大的,在 PHP 中,我們沒有必要再來做 setter 和 getter了。需要引用的屬性,直接使用即可。

2.9、類屬性該聲明還是不聲明

PHP 本身支持屬性可以在使用時增加,也就是不聲明屬性,可以在運行時添加屬性。那么問題來了,事先聲明屬性與事后增加屬性,是否會有性能上的差別。這里也舉一個例子探討一下。

事先聲明了屬性的代碼就是2.8節中,無 setter 的代碼,不再重復。而無屬性聲明的代碼如下:

classUser
{
function getUserInfo()
    {
return "UID:".$this->uid." UserName:".$this->username." Age:".$this->age;
    }
}
for($i=0; $i<1000000;$i++) {
$user = new User();
$user->uid= $i;
$user->age = $i%100;
$user->username="User".$i;
$user->getUserInfo();
}

兩段代碼,運行結果如下:

[root@localhostphpperf]# time php7 object.php
real 0m0.608s
user 0m0.604s
sys 0m0.003s
[root@localhostphpperf]# time php7 object.php
real 0m0.615s
user 0m0.605s
sys 0m0.003s
[root@localhostphpperf]# time php7 object3.php
real 0m0.733s
user 0m0.728s
sys 0m0.004s
[root@localhostphpperf]# time php7 object3.php
real 0m0.727s
user 0m0.720s
sys 0m0.004s

從上面的運行可以看到,無屬性聲明的代碼慢了20%。可以推斷出來的就是對于對象的屬性,如果事先知道的話,我們還是事先聲明的好,這一方面是效率問題,另一方面,也有助于提高代碼的可讀性呢。

2.10、圖片操作 API 的效率差別

在圖片處理操作中,一個非常常見的操作是將圖片縮放成小圖。縮放成小圖的辦法有多種,有使用 API 的,有使用命令行的。在 PHP 中,有 iMagick 和 gmagick 兩個擴展可供操作,而命令行則一般使用 convert 命令來處理。我們這里來討論使用 imagick 擴展中的 API 處理圖片的效率差別。

先上代碼:

function imagick_resize($filename, $outname)
{
$thumbnail = new Imagick($filename);
$thumbnail->resizeImage(200, 200, imagick::FILTER_LANCZOS, 1);
$thumbnail->writeImage($outname);
unset($thumbnail);
}
function imagick_scale($filename, $outname)
{
$thumbnail = new Imagick($filename);
$thumbnail->scaleImage(200, 200);
$thumbnail->writeImage($outname);
unset($thumbnail);
}
function convert($func)
{
$cmd= "find /var/data/ppt |grep jpg";
$start = microtime(true);
exec($cmd, $files);
$index = 0;
foreach($files as $key =>$filename)
    {
$outname= " /tmp/$func"."_"."$key.jpg";
$func($filename, $outname);
$index++;
    }
$end = microtime(true);
echo "$func $index files: " . ($end- $start) . "s\n";
}
convert("imagick_resize");
convert("imagick_scale");

在上面的代碼中,我們分別使用了 resizeImage 和 scaleImage 來進行圖片的壓縮,壓縮的是常見的 1-3M 之間的數碼相機圖片,得到如下運行結果:

[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 5.0612308979034s
imagick_ scale 169 files: 3.1105840206146s
[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 4.4953861236572s
imagick_ scale 169 files: 3.1514940261841s
[root@localhostphpperf]# php55 imagick.php
imagick_ resize 169 files: 4.5400381088257s
imagick_ scale 169 files: 3.2625908851624s

169張圖片壓縮,使用 resizeImage 壓縮,速度在4.5S以上,而使用 scaleImage 則在 3.2S 左右,快了將近50%,壓縮的效果,用肉眼看不出明顯區別。當然 resizeImage 的控制能力更強,不過對于批量處理而言,使用 scaleImage 是更好的選擇,尤其對頭像壓縮這種頻繁大量的操作。本節只是例舉了圖片壓縮 API 作為例子,也正像 explode 和 preg_ split 一樣,在 PHP 中,完成同樣一件事情,往往有多種手法。建議采用效率高的做法。

以上就是關于 PHP 開發的10個方面的對比,這些點涉及到 PHP 語法、寫法以及 API 的使用。有些策略隨著 PHP 的發展,有的已經不再適用,有些策略則會一直有用。

有童鞋也許會說,在現實的開發應用中,上面的某些觀點和解決策略,有點「然并卵」。為什么這么說呢?因為在一個程序的性能瓶頸中,最為核心的瓶頸, 往往并不在 PHP 語言本身。即使是跟 PHP 代碼中暴露出來的性能瓶頸,也常在外部資源和程序的不良寫法導致的瓶頸上。于是為了做好性能分析,我們需要向 PHP 的上下游戲延伸,比如延伸到后端的服務上去,比如延伸到前端的優化規則。在這兩塊,都有了相當多的積累和分析,雅虎也據此提出了多達35條前端優化規則, 這些同 PHP 本身的性能分析構成了一個整體,就是降低用戶的訪問延時。

所以前面兩部分所述的性能分析,只是有助于大家了解 PHP 開發本身,寫出更好的 PHP 程序,為你成為一個資深的 PHP 程序員打下基礎,對于實際生產中程序的效率提升,往往幫助也不是特別顯著,因為大家也看到,在文章的實例中,很多操作往往是百萬次才能看出明顯的性能差別。在現實的頁面中,每一個請求很快執行完成,對這些基礎代碼的調用,往往不會有這么多次調用。不過了解這些,總是好的。

那么,對于一個程序而言,其他的性能瓶頸可能存在哪里?我們將深入探討。所以在本系列的下兩篇,我們將探討 PHP 程序的外圍效源的效率問題和前端效率問題,敬請期待。

責任編輯:王雪燕 來源: oneapm
相關推薦

2015-08-18 11:44:02

PHP性能分析宏觀分析

2024-12-30 10:03:11

2023-12-31 19:41:04

PHP性能終端

2011-03-22 13:00:47

Nagios

2022-07-15 08:52:03

Linux優化

2009-07-06 18:29:55

2013-03-21 11:20:00

性能測試性能調優測試

2023-12-13 09:08:26

CPU性能分析Linux

2023-09-18 16:14:35

性能測試開發

2011-07-20 14:29:33

HBase

2022-04-12 12:35:02

Linux啟動性能systemd

2016-06-14 14:50:17

Python性能

2025-08-04 03:05:00

2025-08-04 02:15:00

2017-06-12 18:48:00

Android性能分析工具

2009-11-23 16:17:02

Visual Stud

2019-10-31 11:50:19

MySQL數據庫Windows

2025-05-22 10:15:59

JITWatchJava

2023-02-02 09:13:12

Hive壓縮使用性能分析

2014-07-28 09:52:14

PythonPython性能
點贊
收藏

51CTO技術棧公眾號

影音先锋欧美激情| 国产高清一区在线观看| 禁久久精品乱码| 精品亚洲va在线va天堂资源站| 91av资源网| 永久av在线| 成人丝袜18视频在线观看| 欧美壮男野外gaytube| 久久噜噜色综合一区二区| 老牛影视av一区二区在线观看| 在线观看一区二区精品视频| a级片一区二区| 国产精品久久久久一区二区国产 | 亚洲精品久久7777| 久久久久久久免费| 99久久一区二区| 日韩国产在线一| 久久久久久久久久久免费精品 | 欧美自拍偷拍| 亚洲精品理论电影| 制服下的诱惑暮生| 成人国产精品一区二区免费麻豆| 午夜电影一区二区| 黄色一级视频播放| 午夜在线播放| 久久久久九九视频| 国产欧美日本在线| 99热这里只有精品9| 免费在线一区观看| 欧美中文字幕在线视频| 久久久一区二区三区四区| 久久密一区二区三区| 亚洲欧美综合v| 亚洲激情 欧美| 日韩一级淫片| 91精品国产色综合久久ai换脸| 五月婷婷狠狠操| 户外露出一区二区三区| 欧美午夜精品久久久久久浪潮 | 丁香花在线影院| 亚洲乱码国产乱码精品精可以看| 亚洲免费不卡| 高清在线观看av| 久久色.com| 久久久精品动漫| 色视频免费在线观看| 波多野结衣91| 精品国产乱码久久久久久久软件| 亚洲精品911| 国产成人超碰人人澡人人澡| 91在线直播亚洲| 国内毛片毛片毛片毛片| 国产真实乱子伦精品视频| 成人激情黄色网| 污污的网站18| 成人性生交大片免费网站| 午夜av区久久| 亚洲自偷自拍熟女另类| 国产免费拔擦拔擦8x在线播放 | 秋霞一区二区三区| 91精品久久久久久蜜臀| 中文字幕12页| 亚洲1区在线观看| 精品国产乱码久久久久久牛牛| 国产综合色一区二区三区| 国产wwwwwww| 国产91丝袜在线播放| 国产伦视频一区二区三区| 日韩在线视频第一页| www.成人网.com| 蜜桃狠狠色伊人亚洲综合网站| 欧美视频综合| 国产精品久久久久婷婷二区次| 一区二区三区的久久的视频| 黄视频网站在线| 亚洲国产你懂的| 免费看的黄色大片| av成人在线播放| 欧美精品色综合| xxxx视频在线观看| 欧美日韩播放| www.日韩.com| 国产无码精品一区二区| 鲁大师成人一区二区三区| 麻豆精品国产传媒mv男同| 国产日韩欧美高清免费| 亚洲一品av免费观看| 欧美色图17p| 欧美精品观看| 日本精品性网站在线观看| 艳妇乳肉豪妇荡乳av| 国产精品一区免费在线观看| 精品无码久久久久国产| a天堂在线资源| 夜夜爽夜夜爽精品视频| 精品视频无码一区二区三区| 国产精品日本一区二区不卡视频| 日韩av在线不卡| 男人的午夜天堂| 亚洲深夜激情| 亚洲aaa激情| 精品视频一二三| 亚洲狼人国产精品| 亚洲性生活网站| 成人午夜大片| 久久精品国产91精品亚洲| 国产又色又爽又黄的| 久久精品免费观看| 欧美精品一区二区三区在线四季| 美女国产在线| 欧美性精品220| 国产一区二区在线观看免费视频| 日本午夜精品久久久| 欧美xxxx做受欧美.88| 波多野结衣爱爱| 不卡的av在线播放| 日韩视频一二三| 成人网ww555视频免费看| 亚洲国产成人在线播放| 日韩三级在线观看视频| 日韩成人一区二区三区在线观看| 国产精品一区二区欧美| 国产三区视频在线观看| 欧美日韩中文字幕一区| 国产精品无码一区二区三区| 中文字幕日韩一区二区不卡| 91精品国产综合久久男男| 精品视频二区| 高跟丝袜一区二区三区| 国产免费a级片| 欧美国产高潮xxxx1819| 91久久久久久久久| 在线看免费av| 欧美一a一片一级一片| 欧美性xxxx图片| 日韩午夜在线| 国产伦精品一区二区三区四区视频| 在线中文字幕电影| 91精品国产综合久久婷婷香蕉 | 亚洲精品字幕在线| 一区二区三区 在线观看视频| 人人爽人人爽av| 小说区亚洲自拍另类图片专区| 国产精品一区二区在线| 国产在线观看黄| 91福利在线免费观看| a级片在线观看| 日韩黄色一级片| 日韩欧美在线电影| 国产69精品久久| 综合网中文字幕| 91极品身材尤物theporn| 国产精品视频九色porn| 爱爱爱爱免费视频| 女生裸体视频一区二区三区| 91大片在线观看| 午夜成年人在线免费视频| 欧美一区二区三区的| 久久免费看少妇高潮v片特黄| 国产麻豆精品在线| 日本xxxxxxxxxx75| 任你弄精品视频免费观看| 欧美最猛性xxxx| jzzjzzjzz亚洲成熟少妇| 欧美美女喷水视频| 欧美日韩人妻精品一区二区三区 | 成人免费在线一区二区三区| 国内在线视频| 日韩激情在线视频| 少妇无套内谢久久久久| 成人欧美一区二区三区黑人麻豆| 免费人成视频在线播放| 亚洲国产婷婷| 欧美日韩一区二区三区在线视频| av一区在线| 久久久精品久久| 日本xxxx人| 色久综合一二码| 久久久精品少妇| 99视频一区二区三区| 日韩av一二三四| 综合天天久久| 久久综合九色欧美狠狠| 深夜日韩欧美| 国内精品久久久久久久久| 韩国三级av在线免费观看| 欧美精品久久天天躁| 国产午夜激情视频| 国产农村妇女精品| 国产无套精品一区二区三区| 日韩成人一区二区三区在线观看| 日本一道在线观看| 国产精品嫩草影院在线看| 91免费视频国产| 一个人www视频在线免费观看| 日韩视频一区在线| 日韩午夜影院| 日韩欧美中文一区二区| 国产美女www爽爽爽| 亚洲一区二区偷拍精品| 中国女人特级毛片| 北岛玲一区二区三区四区| xxx国产在线观看| 在线综合视频| 先锋影音男人资源| 欧美日韩一二三四| 国产午夜精品一区| 亚洲欧美在线人成swag| 日本sm极度另类视频| 图片区小说区亚洲| 日韩小视频在线观看| 理论视频在线| 亚洲成人性视频| 国产乱人乱偷精品视频a人人澡| 欧美日韩一区二区免费视频| 欧美激情一区二区视频| 国产精品三级av在线播放| 艳妇乳肉亭妇荡乳av| 国产精品一区二区久久精品爱涩| 亚洲无吗一区二区三区| 欧美日韩四区| 国产亚洲一区二区三区在线观看 | 日韩视频二区| 欧美精品一区二区性色a+v| 国产精品亚洲人成在99www| 国产精品一区二区欧美黑人喷潮水| 在线免费观看亚洲| 国产精品久久久亚洲| 中文一区一区三区高中清不卡免费| 九九精品视频在线观看| 米奇777四色精品人人爽| 国产一区二区三区网站| 青梅竹马是消防员在线| 亚洲精品www久久久| 免费国产精品视频| 欧美一级夜夜爽| 国产乱码精品一区二区| 欧美久久久久久久久中文字幕| jizz国产在线| 91久久久免费一区二区| 欧美日韩综合一区二区三区| 精品日本高清在线播放| 日韩成人免费在线视频| 亚洲午夜电影在线| 国产一级视频在线播放| 亚洲国产精品久久艾草纯爱| 久久久久久久久久久久久久免费看 | 久久青草视频| 国产精品对白刺激| 91精品店在线| 国产日韩在线一区| 成人国产精品一区二区网站| 91系列在线播放| 136导航精品福利| 国产伦精品一区二区三区在线| 久久精品凹凸全集| 久久另类ts人妖一区二区| 亚洲春色h网| 亚洲春色综合另类校园电影| 久久精品播放| 伊人久久在线观看| 在线观看日韩av电影| 免费国产a级片| 天堂一区二区在线| 999在线观看| 国产精品一区二区无线| xxxx黄色片| 国产三级精品三级| 成年人一级黄色片| 午夜精品免费在线观看| 中文字幕在线播| 欧美日本视频在线| 草草视频在线播放| 亚洲欧美日韩中文在线制服| 91精品国产91久久久久游泳池| 久久综合五月天| 国产直播在线| 国产精品亚洲片夜色在线| 日韩精品视频中文字幕| 久久99久久精品国产| 青青草国产免费一区二区下载| 国产在线无码精品| 香蕉亚洲视频| 先锋资源在线视频| 久久久久国产成人精品亚洲午夜| 日本免费网站视频| 天天操天天色综合| 国产一区二区自拍视频| 日韩电视剧在线观看免费网站 | 国产视频一区在线播放| 精品国产欧美日韩不卡在线观看| 欧美日韩国产一区二区三区| 在线视频 91| 亚洲国产精品久久久久秋霞蜜臀 | 亚洲国产精品综合小说图片区| 99久久精品国产亚洲| 制服丝袜成人动漫| 欧美孕妇性xxxⅹ精品hd| 欧美成人第一页| 日韩a**中文字幕| 国产精品视频入口| 99久久夜色精品国产亚洲96 | 亚洲一一在线| 国产亚洲亚洲| 亚洲av午夜精品一区二区三区| 亚洲国产精品二十页| 日本熟妇一区二区| 欧美高清精品3d| 国产黄在线看| 91国内在线视频| 日韩在线网址| 一区二区精品免费视频| 久久狠狠婷婷| 水蜜桃av无码| 亚洲综合久久久久| 国产强被迫伦姧在线观看无码| 亚洲一区二区黄| 色偷偷偷在线视频播放| 国产精品视频入口| 欧美1区3d| 中文字幕日韩久久| 国产精品网曝门| 色老头在线视频| 精品亚洲永久免费精品| 2018av在线| av在线不卡观看| 亚洲a一区二区三区| 久久久久国产一区| 中文字幕av一区二区三区高 | 国产在线视频精品一区| 日本成人免费视频| 91久久免费观看| 国产日本在线视频| 奇门遁甲1982国语版免费观看高清| 丁香五月缴情综合网| 欧美日韩激情四射| 国产成人av一区| 久久久久无码国产精品| 日韩美女在线视频 | 先锋资源久久| 狠狠操狠狠干视频| 成人免费一区二区三区视频| 91成人在线免费| 久久五月天色综合| 欧美另类中文字幕| 日韩欧美一级在线| 国产91丝袜在线观看| 国产精品suv一区二区| 亚洲精品一线二线三线无人区| 欧美极品少妇videossex| 国产精品毛片一区视频| 亚洲经典三级| www.日本高清| 日本精品一区二区三区高清| 国产高清免费av在线| 国产精品久久久久久久美男 | 波多野结衣欧美| cao在线观看| 91免费看`日韩一区二区| 六月丁香激情综合| 亚洲性生活视频在线观看| 欧美xnxx| 公共露出暴露狂另类av| 成人在线视频一区| 69成人免费视频| 在线观看国产成人av片| 国产精久久久| 韩日视频在线观看| 久久久久久久综合狠狠综合| 中文字幕精品一区二区精| 精品久久久av| 日日夜夜精品视频| 久久久999视频| 国产精品三级久久久久三级| jlzzjlzz亚洲女人18| 久久免费视频观看| 精品国产一区二区三区噜噜噜| 6080国产精品| 欧美午夜电影在线| 免费观看成人高潮| 国产精品区一区| 三级在线观看一区二区| 四虎永久免费在线| 精品一区二区电影| 亚洲成人a级片| 国产精品无码一区二区在线| 日本一区二区免费在线观看视频| 国产成人毛毛毛片| 日本国产精品视频| 欧美日韩综合| 欧美激情 一区| 精品美女一区二区三区| 91在线成人| www在线观看免费| 亚洲欧美在线高清| 香蕉视频黄色片| 亚洲精品欧美日韩| 日韩精品电影一区亚洲| 免费在线黄色片| 最近更新的2019中文字幕|