使用vld看php的opcode
之前整理了一篇文章-PHP APC的設定與應用,介紹APC如何安裝、設定、以及為何APC能讓PHP效能更好。APC能提升PHP效能的主因,就是當中所提到的opcode cache。
由於php的執行會先將php code轉成opcode,因此,要瞭解如何寫更有效率的php程式,讓寫出來的php程式效能更好,可以經由opcode來瞭解。Optimize your PHP Code – Tips, Tricks and Techniques這篇文章的說明中提到很多提升php效能的技巧。我們就以opcode來解釋第五點-在for內為何不要使用count()。
何謂opcode?有哪些指令?可以參考官方資料 - PHP: Opcode list - Manual。那…如何看所寫的php code會被轉成怎樣的opcode?
首先,我們需要安裝vld(Vulcan Logic Disassembler)。在FreeBSD下安裝vld很簡單,用port即可
安裝好後,只需要如下簡單的指令就可以看到opcode
下面,我們就使用vld來看count放在for內,php是如何執行的?為了將焦點集中在opcode,for迴圈內就先不放任何程式碼。並且在進入迴圈之前,也故意跑一次count,以便和第二版做比較。
vld所呈現的opcode如上,總共26行。有興趣瞭解上面opcode含意,請見PHP: Opcode list - Manual
接者,將程式碼做修改。不在for中做count動作。來看opcode的變化
vld所顯示的opcode總共22行,和上一版本相比,少了下面4行。
也就是說,當我們使用for ($counter = 0; $counter < count($myarray); $counter++)這樣的程式時,在每次的迴圈執行時都要計算一次陣列的大小。以上面程式的例子,我們只要在for之前跑一次count()即可,不需要每次都使用系統資源去做無意義的計算。
當我們在處理大量資料、或者高流量的系統時,甚至上述兩者的組合時,這樣的小差異就會如成語所說....積沙成塔、聚少成多,而影響了程式執行效能。
當然,換更有力的硬體也能解決。不過,只是修改一下程式寫作方式,就可以改善效能,又何必另花成本?還可以少點電力消耗,為地球盡點力。 :)
不過,有些提升php效能的說法,僅靠opcode似乎看不出差異。
由於php的執行會先將php code轉成opcode,因此,要瞭解如何寫更有效率的php程式,讓寫出來的php程式效能更好,可以經由opcode來瞭解。Optimize your PHP Code – Tips, Tricks and Techniques這篇文章的說明中提到很多提升php效能的技巧。我們就以opcode來解釋第五點-在for內為何不要使用count()。
何謂opcode?有哪些指令?可以參考官方資料 - PHP: Opcode list - Manual。那…如何看所寫的php code會被轉成怎樣的opcode?
首先,我們需要安裝vld(Vulcan Logic Disassembler)。在FreeBSD下安裝vld很簡單,用port即可
cd /usr/ports/devel/pecl-vld
make install
make install
安裝好後,只需要如下簡單的指令就可以看到opcode
php -q -d vld.active=1 opcodetest.php
下面,我們就使用vld來看count放在for內,php是如何執行的?為了將焦點集中在opcode,for迴圈內就先不放任何程式碼。並且在進入迴圈之前,也故意跑一次count,以便和第二版做比較。
<?php $myarray = array('apc', 'opcode', 'test'); $total = count($myarray); for ($counter = 0; $counter < count($myarray); $counter++) { }
filename: /apc/opcodetest.php
function name: (null)
number of ops: 26
compiled vars: !0 = $myarray, !1 = $total, !2 = $counter
line # * op fetch ext return operands
--------------------------------------------------------------------
2 0 > EXT_STMT
1 INIT_ARRAY ~0 'apc'
2 ADD_ARRAY_ELEMENT ~0 'opcode'
3 ADD_ARRAY_ELEMENT ~0 'test'
4 ASSIGN !0, ~0
3 5 EXT_STMT
6 EXT_FCALL_BEGIN
7 SEND_VAR !0
8 DO_FCALL 1 'count'
9 EXT_FCALL_END
10 ASSIGN !1, $2
4 11 EXT_STMT
12 ASSIGN !2, 0
13 > EXT_FCALL_BEGIN
14 SEND_VAR !0
15 DO_FCALL 1 'count'
16 EXT_FCALL_END
17 IS_SMALLER ~6 !2, $5
18 EXT_STMT
19 > JMPZNZ 23 ~6, ->24
20 > POST_INC ~7 !2
21 FREE ~7
22 > JMP ->13
5 23 > > JMP ->20
6 24 > > RETURN 1
25* > ZEND_HANDLE_EXCEPTION
接者,將程式碼做修改。不在for中做count動作。來看opcode的變化
<?php $myarray = array('apc', 'opcode', 'test'); $total = count($myarray); for ($counter = 0; $counter < $total; $counter++) { }
filename: /apc/opcodetest.php
function name: (null)
number of ops: 22
compiled vars: !0 = $myarray, !1 = $total, !2 = $counter
line # * op fetch ext return operands
--------------------------------------------------------------------
2 0 > EXT_STMT
1 INIT_ARRAY ~0 'apc'
2 ADD_ARRAY_ELEMENT ~0 'opcode'
3 ADD_ARRAY_ELEMENT ~0 'test'
4 ASSIGN !0, ~0
3 5 EXT_STMT
6 EXT_FCALL_BEGIN
7 SEND_VAR !0
8 DO_FCALL 1 'count'
9 EXT_FCALL_END
10 ASSIGN !1, $2
4 11 EXT_STMT
12 ASSIGN !2, 0
13 > IS_SMALLER ~5 !2, !1
14 EXT_STMT
15 > JMPZNZ 19 ~5, ->20
16 > POST_INC ~6 !2
17 FREE ~6
18 > JMP ->13
5 19 > > JMP ->16
6 20 > > RETURN 1
21* > ZEND_HANDLE_EXCEPTION
vld所顯示的opcode總共22行,和上一版本相比,少了下面4行。
13 > EXT_FCALL_BEGIN 14 SEND_VAR !0 15 DO_FCALL 1 'count' 16 EXT_FCALL_END
也就是說,當我們使用for ($counter = 0; $counter < count($myarray); $counter++)這樣的程式時,在每次的迴圈執行時都要計算一次陣列的大小。以上面程式的例子,我們只要在for之前跑一次count()即可,不需要每次都使用系統資源去做無意義的計算。
當我們在處理大量資料、或者高流量的系統時,甚至上述兩者的組合時,這樣的小差異就會如成語所說....積沙成塔、聚少成多,而影響了程式執行效能。
當然,換更有力的硬體也能解決。不過,只是修改一下程式寫作方式,就可以改善效能,又何必另花成本?還可以少點電力消耗,為地球盡點力。 :)
不過,有些提升php效能的說法,僅靠opcode似乎看不出差異。
參考資料
留言