成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

翻譯 使用正則的快速路由庫(kù)

Lionad-Morotar / 760人閱讀

摘要:的路由是使用了這個(gè)庫(kù)作者寫了一篇帖子介紹了它寫這個(gè)庫(kù)的原因原文鏈接使用正則的快速路由庫(kù)前段時(shí)間我在路由庫(kù)遇到了一些問(wèn)題。它號(hào)稱比現(xiàn)用的路由庫(kù)快幾個(gè)數(shù)量級(jí)的,因?yàn)闉榱诉_(dá)到這個(gè)這個(gè)目的,這個(gè)庫(kù)是通過(guò)的擴(kuò)展實(shí)現(xiàn)的。

首先先區(qū)分一下概念:
路由是指一個(gè)過(guò)程,就是利用定義好的一些規(guī)則,讓不同的URI能夠調(diào)用不同的處理器(一個(gè)匿名函數(shù)或者一個(gè)類中的方法)這樣一個(gè)過(guò)程。

平常很多框架所說(shuō)的定義一個(gè)路由就是注冊(cè)一個(gè)這樣的規(guī)則到系統(tǒng)中去。

slim的路由是使用了FastRoute這個(gè)庫(kù),作者寫了一篇帖子,介紹了它寫這個(gè)庫(kù)的原因(原文鏈接):

使用正則的快速路由庫(kù)

前段時(shí)間,我在Pux路由庫(kù)遇到了一些問(wèn)題。它號(hào)稱比現(xiàn)用的路由庫(kù)快幾個(gè)數(shù)量級(jí)的,因?yàn)闉榱诉_(dá)到這個(gè)這個(gè)目的,這個(gè)庫(kù)是通過(guò)PHP的C擴(kuò)展實(shí)現(xiàn)的。
然而,粗略地看了Pux的源碼之后,我強(qiáng)烈懷疑這個(gè)庫(kù)優(yōu)化了路由處理的錯(cuò)誤部分,而我不借助于C擴(kuò)展卻可以很輕松地到更好的性能。當(dāng)我看了Pux的基準(zhǔn)測(cè)試之后,發(fā)現(xiàn)只測(cè)試了幾個(gè)非常簡(jiǎn)單實(shí)際的單路由例子,我就更加肯定了我的懷疑。
為了進(jìn)一步調(diào)查這個(gè)問(wèn)題,我寫了一個(gè)小型路由庫(kù):FastRoute,這個(gè)庫(kù)實(shí)現(xiàn)了接下來(lái)描述的分發(fā)處理。為了給出預(yù)先觀點(diǎn),我貼出了和Pux庫(kù)對(duì)比的小型基準(zhǔn)測(cè)試結(jié)果:

1 placeholder  | Pux (no ext) | Pux (ext) | FastRoute
-----------------------------------------------------
First route    | 0.17 s       | 0.13 s    | 0.14 s
Last route     | 2.51 s       | 1.20 s    | 0.49 s
Unknown route  | 2.34 s       | 1.10 s    | 0.34 s

9 placeholders | Pux (no ext) | Pux (ext) | FastRoute
-----------------------------------------------------
First route    | 0.22 s       | 0.19 s    | 0.20 s
Last route     | 2.65 s       | 1.78 s    | 0.59 s
Unknown route  | 2.50 s       | 1.49 s    | 0.40 s

這個(gè)基準(zhǔn)測(cè)試使用了一百個(gè)路由,然后找出其中最快的路由(最佳例子),最慢的路由(最差的例子)和一個(gè)總共的未知平均路由。測(cè)試通過(guò)設(shè)置一個(gè)變量分為兩部分,一部分使用了1個(gè)占位符,另一部分使用了9個(gè)占位符。整個(gè)測(cè)試很明顯進(jìn)行了循環(huán)了幾百次。

關(guān)于路由的問(wèn)題

為了確保我們?cè)谡f(shuō)同一個(gè)事物,讓我們定義一下"路由"是什么。在大多數(shù)實(shí)際的形式中,它是指跟以下形式類似的利用一套路由定義:

$r->addRoute("GET", "/user/{name}/{id:d+}", "handler0");
$r->addRoute("GET", "/user/{id:d+}", "handler1");
$r->addRoute("GET", "/user/{name}", "handler2");

然后調(diào)度處理一個(gè)基于它們的URI的過(guò)程:

$d->dispatch("GET", "/user/nikic/42");
// => provides "handler0" and ["name" => "nikic", "id" => "42"]

把這個(gè)過(guò)程提升到一個(gè)更抽象的層次,我們將會(huì)為路由定義提供HTTP方法和任何特定的格式。在本文中,我會(huì)考慮的唯一一樣事情是路由的調(diào)度階段——路由如何被解析或調(diào)度器生成的數(shù)據(jù)不會(huì)被覆蓋。
那么,路由處理的最耗時(shí)的部分是哪里呢?在一個(gè)混亂不堪的,過(guò)度被設(shè)計(jì)的系統(tǒng)中,它可能是實(shí)例化數(shù)十個(gè)對(duì)象和調(diào)用數(shù)百個(gè)方法的開(kāi)銷。Pux庫(kù)在減少這方面的開(kāi)銷做的很好。然而,在一個(gè)比較原始層次的系統(tǒng)中,依次經(jīng)過(guò)一系列數(shù)十個(gè)或者數(shù)百個(gè)路由表達(dá)式,之后再通過(guò)提供的URI和它們進(jìn)行匹配這個(gè)過(guò)程是最耗時(shí)的部分。讓這個(gè)過(guò)程更快就是本文的主題。
合并的正則表達(dá)式:
優(yōu)化這類問(wèn)題的最基本方法是避免一個(gè)個(gè)的去匹配那些正則表達(dá)式,相反地,把它們結(jié)合在一起,變成一個(gè)大的正則表達(dá)式,這樣的話,你只需要進(jìn)行一次匹配就可以了。就拿最后一個(gè)例子的路由作說(shuō)明,合并的正則表達(dá)式是這樣的:

Individual regexes:

    ~^/user/([^/]+)/(d+)$~
    ~^/user/(d+)$~
    ~^/user/([^/]+)$~

Combined regex:

    ~^(?:
        /user/([^/]+)/(d+)
      | /user/(d+)
      | /user/([^/]+)
    )$~x

這個(gè)轉(zhuǎn)化很簡(jiǎn)單:基本上你只要將那些正則表達(dá)式一個(gè)個(gè)地用OR 連接在一起就可以了。當(dāng)匹配這個(gè)合并的正則表達(dá)式,如何找出具體哪個(gè)路由規(guī)則被匹配了呢?為了找出來(lái),讓我們來(lái)看一看preg_match這個(gè)函數(shù)對(duì)一個(gè)樣本的輸出:

preg_match($regex, "/user/nikic", $matches);
=> [
    "/user/nikic",   # full match
    "", "",          # groups from first route (empty)
    "",              # groups from second route (empty)
    "nikic",         # groups from third route (used!)
]

那么,在$matches數(shù)組中找到第一個(gè)非空入口就是訣竅了(當(dāng)然,沒(méi)算上第一個(gè)完全匹配)。


這里我貼上代碼,方便大家測(cè)試:

$regex = "~^(?:/user/([^/]+)/(d+)|/user/(d+)|/user/([^/]+))$~x";
preg_match($regex, "/user/nikic", $matches);

var_dump($matches);

(?:regexp) 匹配 pattern 但不獲取匹配結(jié)果,也就是說(shuō)這是一個(gè)非獲取匹配,不進(jìn)行存儲(chǔ)供以后使用。這在使用 "或" 字符 (|) 來(lái)組合一個(gè)模式的各個(gè)部分是很有用。例如, "industr(?:y|ies) 就是一個(gè)比 "industry|industries" 更簡(jiǎn)略的表達(dá)式。介紹


為了使用這個(gè)結(jié)果,你將需要一個(gè)額外的數(shù)據(jù)結(jié)構(gòu)來(lái)映射$matches的索引到匹配的路由規(guī)則(或者,一些關(guān)聯(lián)那個(gè)路由規(guī)則的信息)

[
    1 => ["handler0", ["name", "id"]],
    3 => ["handler1", ["id"]],
    4 => ["handler2", ["name"]],
]

這里是一個(gè)實(shí)現(xiàn)整個(gè)處理流程的例子:

public function dispatch($uri) {
    if (!preg_match($this->regex, $uri, $matches)) {
        return [self::NOT_FOUND];
    }

    // find first non-empty match (skipping full match)
    for ($i = 1; "" === $matches[$i]; ++$i);

    list($handler, $varNames) = $this->routeData[$i];

    $vars = [];
    foreach ($varNames as $varName) {
        $vars[$varName] = $matches[$i++];
    }
    return [self::FOUND, $handler, $vars];
}

在找到第一個(gè)非空的索引,關(guān)聯(lián)的數(shù)據(jù)就可以被查找到了。通過(guò)遍歷$matches數(shù)組并配對(duì)值和變量名,占位符的變量就可以被填充了。
那么這個(gè)方法執(zhí)行起來(lái)效率如何呢?這里給出了和Pux的比較結(jié)果(使用C擴(kuò)展):

1 placeholder  | Pux (ext) | GPB-NC
-----------------------------------
First route    | 0.13 s    | 0.20 s
Last route     | 1.20 s    | 0.70 s
Unknown route  | 1.10 s    | 0.16 s

9 placeholders | Pux (ext) | GPB-NC
-----------------------------------
First route    | 0.19 s    | 0.41 s
Last route     | 1.78 s    | 4.09 s
Unknown route  | 1.49 s    | 0.30 s

GPB-NC表示“Group position based, non-chunked”調(diào)度。如你所見(jiàn)的那樣,在單個(gè)占位符的測(cè)試?yán)舆@個(gè)方法提供了不錯(cuò)的性能。當(dāng)然它不能打敗在最快路由上正確匹配的C擴(kuò)展實(shí)現(xiàn),但是在最糟糕匹配上,它表現(xiàn)地快了一點(diǎn),如果一個(gè)都沒(méi)匹配的話,更快了。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/23212.html

相關(guān)文章

  • 前端資源分享-只為更好前端

    摘要:一團(tuán)隊(duì)組織網(wǎng)站說(shuō)明騰訊團(tuán)隊(duì)騰訊前端團(tuán)隊(duì),代表作品,致力于前端技術(shù)的研究騰訊社交用戶體驗(yàn)設(shè)計(jì),簡(jiǎn)稱,騰訊設(shè)計(jì)團(tuán)隊(duì)網(wǎng)站騰訊用戶研究與體驗(yàn)設(shè)計(jì)部百度前端研發(fā)部出品淘寶前端團(tuán)隊(duì)用技術(shù)為體驗(yàn)提供無(wú)限可能凹凸實(shí)驗(yàn)室京東用戶體驗(yàn)設(shè)計(jì)部出品奇舞團(tuán)奇虎旗下前 一、團(tuán)隊(duì)組織 網(wǎng)站 說(shuō)明 騰訊 AlloyTeam 團(tuán)隊(duì) 騰訊Web前端團(tuán)隊(duì),代表作品WebQQ,致力于前端技術(shù)的研究 ISUX 騰...

    zxhaaa 評(píng)論0 收藏0
  • 前端資源分享-只為更好前端

    摘要:一團(tuán)隊(duì)組織網(wǎng)站說(shuō)明騰訊團(tuán)隊(duì)騰訊前端團(tuán)隊(duì),代表作品,致力于前端技術(shù)的研究騰訊社交用戶體驗(yàn)設(shè)計(jì),簡(jiǎn)稱,騰訊設(shè)計(jì)團(tuán)隊(duì)網(wǎng)站騰訊用戶研究與體驗(yàn)設(shè)計(jì)部百度前端研發(fā)部出品淘寶前端團(tuán)隊(duì)用技術(shù)為體驗(yàn)提供無(wú)限可能凹凸實(shí)驗(yàn)室京東用戶體驗(yàn)設(shè)計(jì)部出品奇舞團(tuán)奇虎旗下前 一、團(tuán)隊(duì)組織 網(wǎng)站 說(shuō)明 騰訊 AlloyTeam 團(tuán)隊(duì) 騰訊Web前端團(tuán)隊(duì),代表作品WebQQ,致力于前端技術(shù)的研究 ISUX 騰...

    JouyPub 評(píng)論0 收藏0
  • 前端資源分享-只為更好前端

    摘要:一團(tuán)隊(duì)組織網(wǎng)站說(shuō)明騰訊團(tuán)隊(duì)騰訊前端團(tuán)隊(duì),代表作品,致力于前端技術(shù)的研究騰訊社交用戶體驗(yàn)設(shè)計(jì),簡(jiǎn)稱,騰訊設(shè)計(jì)團(tuán)隊(duì)網(wǎng)站騰訊用戶研究與體驗(yàn)設(shè)計(jì)部百度前端研發(fā)部出品淘寶前端團(tuán)隊(duì)用技術(shù)為體驗(yàn)提供無(wú)限可能凹凸實(shí)驗(yàn)室京東用戶體驗(yàn)設(shè)計(jì)部出品奇舞團(tuán)奇虎旗下前 一、團(tuán)隊(duì)組織 網(wǎng)站 說(shuō)明 騰訊 AlloyTeam 團(tuán)隊(duì) 騰訊Web前端團(tuán)隊(duì),代表作品WebQQ,致力于前端技術(shù)的研究 ISUX 騰...

    vslam 評(píng)論0 收藏0
  • [nginx文檔翻譯系列]新手指南

    摘要:主進(jìn)程的目的是為了讀取和評(píng)估配置并保持工作進(jìn)程。默認(rèn)情況下,這個(gè)配置文件名為。如果一個(gè)塊指令在大括號(hào)中有其他的指令,則稱之為上下文如和。放在配置文件最外面的指令的稱之為主文,指令在主文中在中,在中。注意指令已經(jīng)被放置在環(huán)境中。 原文鏈接:http://nginx.org/en/docs/begi...轉(zhuǎn)自我的github有些地方覺(jué)得翻譯的不是很合理,所以在括號(hào)中寫出了原句。如果有地方翻...

    jk_v1 評(píng)論0 收藏0
  • [nginx文檔翻譯系列]新手指南

    摘要:主進(jìn)程的目的是為了讀取和評(píng)估配置并保持工作進(jìn)程。默認(rèn)情況下,這個(gè)配置文件名為。如果一個(gè)塊指令在大括號(hào)中有其他的指令,則稱之為上下文如和。放在配置文件最外面的指令的稱之為主文,指令在主文中在中,在中。注意指令已經(jīng)被放置在環(huán)境中。 原文鏈接:http://nginx.org/en/docs/begi...轉(zhuǎn)自我的github有些地方覺(jué)得翻譯的不是很合理,所以在括號(hào)中寫出了原句。如果有地方翻...

    phoenixsky 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<