中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP7的FAST_ZPP內核用法

發布時間:2020-06-09 09:17:16 來源:億速云 閱讀:274 作者:Leah 欄目:編程語言

這篇文章主要介紹了PHP7的FAST_ZPP內核的使用方法,具有一定借鑒價值,需要的朋友可以參考下。如下資料是關于FAST_ZPP的詳細步驟內容。

從PHP7開始,大家可能會發現,不少函數不再使用傳統的參數處理方式,而是改用了我們稱之為Fast zend parameters parsing(FAST_ZPP)的新型方式, 比如在PHP7之前,count函數是這樣的:

PHP_FUNCTION(count)
{
    zval *array;
    long mode = COUNT_NORMAL;
 
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {
        return;
    }
    ....
}

在PHP7以后,變成了:

PHP_FUNCTION(count)
{
    zval *array;
    zend_long mode = COUNT_NORMAL;
 
    ZEND_PARSE_PARAMETERS_START(1, 2)
        Z_PARAM_ZVAL(array)
        Z_PARAM_OPTIONAL
        Z_PARAM_LONG(mode)
    ZEND_PARSE_PARAMETERS_END();
    ...
}

很多PHP擴展開發的同學可能在初次接觸的時候,會覺得很陌生,不要焦慮,讓我慢慢道來 :)

當時在做PHPNG(PHP7的開發項目代號)的開發的時候,我們主要的發現性能提升點的一個方式就是bench各種大型實際項目,來發現占用資源比較大的部分,而最常用benchmark對象之一是wordpress,因為它夠復雜,夠慢,(它也是我們開發JIT的時候對主要bench目標:)) 代表了非OO型代碼類的典型應用, 在實際的benchmark的過程中我們發現,將近有6%的耗時被zend_parse_parameters給占用了。

事實上zend_parameters_parsing確實是一個很龐大的函數:

ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...)

它根據type_spec字符串中指定的標識符,來處理輸入參數,而這個參數符有很多種(具體含義可以參看: README.PARAMETER_PARSING_API):

a A b C d f h H l L o O p P r s S z * + | / !

根據不同的組合來表示我們的PHP函數要接受的參數類型,比如例子中的count, 通過”z|l”表示要接受一個zval類型的參數,和一個可選的long類型的mode參數,當zend_parse_parameters在runtime的時候被調用的時候,就會需要分析這些字符,然后調用對應的邏輯,對于一些本身就很簡單的函數來說,比如count,這個開銷就會顯得很明顯。

再回頭來看這個函數的特點,我們會發現,比如對于count這個例子來說,其實type_spec在編譯期就是確定的常量,也就是說,其實在編譯的時候,我們就應該已經知道了”a|l”應該調用那些對應的參數處理邏輯。

而事實上,當代的編譯器都具備這個基本優化能力, 比如對于如下的代碼:

#include <stdlib.h>
 
#define AAA  1;
int main() {
    int a = AAA;
    if (a) {
        abort();
    }
    return 0;
}

如果我們嘗試讓編譯優化(-o2)它,并檢查生成的匯編:

main:
.LFB18:
    subq    $8, %rsp
    call    abort@PLT

大家可以看到,if判斷已經被抹掉了, 因為在編譯時刻, 就能知道a是1, if一定為真。

而FAST_ZPP就是充分借助了這個能力而來的一種新型的參數申明方式, 比如對于Z_PARAM_ZVAL(array)

#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \
        if (separate) { \
            Z_PARAM_PROLOGUE(separate); \
            zend_parse_arg_zval_deref(_arg, &dest, check_null); \
        } else { \
            ++_i; \
            ZEND_ASSERT(_i <= _min_num_args || _optional==1); \
            ZEND_ASSERT(_i >  _min_num_args || _optional==0); \
            if (_optional && UNEXPECTED(_i >_num_args)) break; \
            _real_arg++; \
            zend_parse_arg_zval(_real_arg, &dest, check_null); \
        }
 
#define Z_PARAM_ZVAL(dest) \
    Z_PARAM_ZVAL_EX(dest, 0, 0)

在編譯時刻就能被先替換為:

zend_parse_arg_zval(((zval*)execute_data) - 1, &array, 0);

而如果我們進一步審視zend_parse_arg_zval:

static zend_always_inline void zend_parse_arg_zval(zval *arg, zval **dest, int check_null)
{
    *dest = (check_null &&
        (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) ||
         (UNEXPECTED(Z_ISREF_P(arg)) &&
          UNEXPECTED(Z_TYPE_P(Z_REFVAL_P(arg)) == IS_NULL)))) ? NULL : arg;
}

我們會發現它也是一個inline申明的函數,而參數因為是常量,那么就可以進一步被evaluate成:

zval *array = ((zval*)execute_data) - 1;

怎么樣,是不是一看就知道會快很多? 沒有type_spec分析,沒有額外的函數調用,直接獲取到參數。

剛剛說到的inline函數可以在編譯時期根據常數的剪枝內聯, 也是用來避免同類函數的重復代碼的很好的方法,在PHP7中也有大量使用,有興趣的可以參看zend_hash.c中的很多相似函數的定義。

當然,這么做也有一個問題就是, 會增大我們程序的binary size, 這個也很容易理解, 比如對于count來說,本來原來只是調用一個外部函數,一個call指令就夠了,但現在就會有很多內聯進來的指令。

而binary size變大以后,執行時期的cache miss就會增大,也會影響性能,所以FAST_ZPP我們也不是建議全部使用, 而真是針對實際應用中調用頻率比較大,并且本身函數邏輯較為簡單的函數來使用.

總結一下,一般來說,我們自己寫的擴展函數,并不需要一定使用FAST_ZPP, 因為如果自身是復雜的函數邏輯的, 這點開銷對比起來,其實也還好了。

最后,附上新的FAST_ZPP API和老的參數描述之間的對應如下:

PHP7的FAST_ZPP內核用法

以上就是PHP7的FAST_ZPP內核的詳細內容了,看完之后是否有所收獲呢?如果想了解更多相關內容,歡迎關注億速云行業資訊!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

时尚| 浦县| 万山特区| 新密市| 广宁县| 弋阳县| 耒阳市| 高陵县| 廉江市| 青冈县| 金门县| 雅安市| 乐都县| 定南县| 北票市| 和顺县| 独山县| 射阳县| 通化市| 郸城县| 华蓥市| 重庆市| 江山市| 遵化市| 武隆县| 安泽县| 许昌县| 大埔县| 诏安县| 武陟县| 泽库县| 大竹县| 巍山| 社旗县| 普兰县| 洞口县| 洪洞县| 鸡泽县| 正安县| 洛阳市| 双城市|