【PHP】php7新特性及其優化原理


PHP7新特性

 

php7.x增加的新特性介紹可以參考這里:

 https://www.runoob.com/php/php7-new-features.html

 https://php.net/manual/zh/migration70.new-features.php

php7.x版本系列相比之前的php的版本提交性能提高了不少,下圖是wordpress在不同php版本下的壓力測試表現。

 

 

這里面其中的一些主要改變是性能提高的關鍵,主要有以下內容。

 

1.zval使用棧內存


 

  在zend引擎和擴展中,經常要創建php變量,其底層就是一個zval指針,之前的php版本都是通過MAKE_STD_ZVAL動態的從堆內存上分配一個zval內存。而php7直接使用棧內存,好處是少了一次內存分配。php程序中回大量創建變量,所以php7會在棧上預分配一塊內存來存放這些zval,來節省大量的內存分配和管理操作。

  php5

zval *val ; MAKE_STD_ZVAL(val)

 php7

zval val;

 

2.zend_string存儲hash值,array查詢不再需要重復計算hash


 

  數組是php比較重要的數據結構,php程序中會有大量的array關聯查詢,雖然hashtable查找的復雜度是O(1),但是key的值每次要轉化成一個hash值,需要用一個復雜的hash函數去計算的,這樣就會占用cpu時間,不過不光數組,在php底層很多地方都會用到hashtable,比如類的屬性方法函數等。其實php程序運行起來大部分key的值是不變的,所以php7就保存了這些hash值下次直接使用,那么php7就為字符串單獨創建了新類型叫做zend_string,除了char*指針和長度之外,增加了一個hash字段,用於保存字符串的hash值,數據鍵值查找不再反復需要計算hash值。為了優化數組的鍵值查找。

 上圖代碼中 zend_ulong h;就是存儲hash值。

 

3.hashtable桶內直接存放數據,減少了內存申請次數,順便也提升了cache命中率和訪問速度。因為指針不是連續的是分布在不同的內存頁上,如果讀取第一個或者第三個桶,它們的數據可能會在兩個頁上。


 

php7之前

 

數據存放是在上圖arBuckets這個結構體上,存放了一些bucket * 指針,指針上就是對應了一些數據。php7對這些做了一些改進,如下圖。

php7

 

 php7將之前arBuckets改成了上圖中的arData,而這個arData直接就是一個大塊內存,這個內存上面就是一個個桶bucket,這樣的好處就是每次數據就不需要動態去申請內存。

 

4.zend_parse_parameters改為宏實現,性能提升15%。

5.新增加4種opcode,call_user_function(),is_int(),is_string(),is_array(),strlen(),defined() 4個函數變為php opcode指令,速度更快。

6.PHP7 的內核中有一個重要的變化是加入了 AST(Abstract syntax tree)抽象語法樹,指代碼在計算機內存的一種樹狀數據結構,樹上的每個節點都表示源代碼中的一種結構,便於計算機理解和解析。

 在 PHP5系列版本中,從 php 腳本到 opcodes 的執行的過程如下:

  1. 詞法掃描分析(Lexing):將源文件轉換成 token 流;

  2. 語法分析(Parsing):生成 op arrays。

 PHP7 中在語法分析階段先生成 AST:

  1. 詞法掃描分析(Lexing):將源文件轉換成 token 流。

  2. 語法分析(Parsing):從 token 流生成抽象語法樹。

  3. Compilation:從抽象語法樹生成 op arrays。    

    這個表達式($a)['b'] = 1 就會被解析成下圖這樣的一棵樹結構

  

7.其他更多性能優化,如基礎類型 float , int , bool等改成直接進行值拷貝。排序算法改進了,PCER with JIT , execute_data和opline使用全局寄存器,使用gdb4.8的PGO功能。

8.php7與JIT

  最初HHVM退出一個很重要的特性就是JIT,JIT就是just in time的縮寫,表示運行時候將指令轉換成二進制機器碼,我們知道C和C++是將源代碼編譯然后生成二進制機器碼去執行的,而php,python等腳本語言是將源代碼轉換成中間指令然后在vm(虛擬機)上執行,另外java系語言他們使用的JVM引擎底層也是JIT,是將java的字節碼編譯成二進制的機器碼去執行的。對於計算密集型的的程序,JIT可以將PHP的opcode直接轉換成機器碼,可以大幅度提升PHP性能。

  不過PHP7.0-final版本中不會帶有JIT特性的。

  但是

  為什么php7版本沒有使用JIT呢?

  是因為php官方之前有個php中間版本是帶有JIT的,后來php官方開發組使用JIT測試時候發現JIT對於實際項目的性能沒有太大的性能提升,所以最終放棄使用JIT方案。但后來發現密集計算性的php程序使用JIT后性能還會大幅提升。

 

 

PHP7下載與安裝

 1.第一步  下載源代碼
wget https://www.php.net/distributions/php-7.2.21.tar.bz2 
2.第二步 解壓源代碼 tar -xjvf php-7.2.21.tar.bz2
3.第三步 進入目錄 cd php-7.2.21
4.第四步 執行configure shell腳本檢測環境及配置php安裝目錄 比如檢測php安裝是否必須要有gcc 和 authconfig等工具 ./configure --prefix=/usr/local/src/php7

出現下面提示說明上面執行成功
Generating files configure: creating .
/config.status creating main/internal_functions.c creating main/internal_functions_cli.c +--------------------------------------------------------------------+ | License: | | This software is subject to the PHP License, available in this | | distribution in the file LICENSE. By continuing this installation | | process, you are bound by the terms of this license agreement. | | If you do not agree with the terms of this license, you must abort | | the installation process at this point. | +--------------------------------------------------------------------+ Thank you for using PHP. 5.第五步 編譯安裝 make && make install

出現下面提示說明make成功
clicommand.inc
directorygraphiterator.inc
invertedregexiterator.inc
pharcommand.inc
phar.inc

Build complete.
Don't forget to run 'make test'.

出現下面提示說明make install成功
Installing PEAR environment:      /usr/local/src/php7/lib/php/
[PEAR] Archive_Tar    - installed: 1.4.7
[PEAR] Console_Getopt - installed: 1.4.2
[PEAR] Structures_Graph- installed: 1.1.1
[PEAR] XML_Util       - installed: 1.4.3
[PEAR] PEAR           - installed: 1.10.9
Wrote PEAR system config file at: /usr/local/src/php7/etc/pear.conf
You may want to add: /usr/local/src/php7/lib/php to your php.ini include_path
/usr/local/src/php-7.2.21/build/shtool install -c ext/phar/phar.phar /usr/local/src/php7/bin
ln -s -f phar.phar /usr/local/src/php7/bin/phar
Installing PDO headers:           /usr/local/src/php7/include/php/ext/pdo/

 驗證php安裝成功

songguojundeMBP:php7 songguojun$ pwd
/usr/local/src/php7
songguojundeMBP:php7 songguojun$ ls
bin    etc    include    lib    php    var
songguojundeMBP:php7 songguojun$ cd bin/
songguojundeMBP:bin songguojun$ ./php -v  #顯示php版本  下面打印出php版本說明php安裝成功
PHP 7.2.21 (cli) (built: Feb 22 2019 22:19:32) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies

 如果php命令找不到就添加到啟動文件中

songguojundeMBP:~ songguojun$ vim ~/.bash_profile
alias ll='ls -alF'
alias la='ls -A'
export PATH="/usr/local/opt/libiconv/bin:$PATH" alias php=/usr/local/src/php7/bin/php

songguojundeMBP:~ songguojun$ source ~/.bash_profil

 

 

源碼安裝可能會出現的問題:

1. 缺少libiconv提示
checking for iconv support... yes
checking for iconv... no
checking for libiconv... no
configure: error: Please specify the install prefix of iconv with --with-iconv=<DIR>
 下載libiconv庫
 brew install libiconv
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM