
做文本處理的團(tuán)隊(duì)經(jīng)常會(huì)遇到類似的情況一段代碼要在內(nèi)存里快速掃過把里面的字母統(tǒng)一折疊成小寫供后面的大小寫不敏感匹配使用。數(shù)據(jù)量一大第一反應(yīng)就是把檢測(cè)和轉(zhuǎn)換合并成一趟心想少讀一遍內(nèi)存總是快的。GitHub 工程師最近在博客里記錄了一次完整的對(duì)比實(shí)驗(yàn)結(jié)論和直覺正好相反兩趟分開做吞吐量是融合方案的 2.6 倍。融合一趟為什么輸給了拆成兩趟這個(gè)問題的場(chǎng)景是處理源代碼文本在 64 位系統(tǒng)上每 16 字節(jié)檢測(cè)一次用兩個(gè) u64 通道做或運(yùn)算再拿一個(gè) 0x8080_8080_8080_8080 掩碼檢查高位。檢測(cè)階段不寫內(nèi)存轉(zhuǎn)換階段用向量化指令一次處理 16 字節(jié)。先試的是把兩者融合檢測(cè)到非 ASCII 字符就當(dāng)場(chǎng)轉(zhuǎn)換數(shù)據(jù)只讀一遍。結(jié)果很尷尬吞吐量只有 8.7 GiB/s。拆成兩階段后先無分支地掃描確認(rèn) ASCII 前綴再單獨(dú)做向量化轉(zhuǎn)換吞吐量到了 23 GiB/s——將近三倍差距。問題出在分支上。融合方案每 16 字節(jié)就要做一次分支判斷編譯器看到分支就沒法對(duì)整個(gè)循環(huán)做向量化內(nèi)層轉(zhuǎn)換即使還能向量化也扛不住外層分支帶來的延遲。GitHub 工程師的判斷是在熱點(diǎn)循環(huán)里分支開銷對(duì)性能的殺傷力遠(yuǎn)大于多讀一遍數(shù)據(jù)。數(shù)據(jù)訪問次數(shù)減半但分支導(dǎo)致編譯器放棄優(yōu)化整體反而更慢。預(yù)分配緩沖區(qū)里的第二個(gè)取舍兩階段方案還有個(gè)細(xì)節(jié)為了避免內(nèi)存增長(zhǎng)觸發(fā)的重分配用預(yù)分配緩沖區(qū)只在必要時(shí)才擴(kuò)展。這換來了另一個(gè)權(quán)衡——檢測(cè)階段和轉(zhuǎn)換階段都要讀一遍數(shù)據(jù)內(nèi)存帶寬壓力是融合方案的兩倍。這里其實(shí)是兩個(gè)取舍疊在一起一個(gè)是少讀數(shù)據(jù)對(duì)無分支可向量化另一個(gè)是避免重分配對(duì)帶寬翻倍。GitHub 的結(jié)論是前者后者都選了后者實(shí)測(cè)數(shù)據(jù)支持這個(gè)選擇。但不要把這個(gè)結(jié)論推廣成兩趟永遠(yuǎn)比一趟快。這次能贏前提是檢測(cè)階段做到了完全無分支并且轉(zhuǎn)換階段能被編譯器向量化。如果檢測(cè)邏輯本身復(fù)雜到無法消除分支或者數(shù)據(jù)源不在內(nèi)存里而在磁盤上兩趟讀的成本結(jié)構(gòu)就完全不一樣了。融合方案在有些場(chǎng)景仍然合理這次實(shí)驗(yàn)說明的是少讀一遍數(shù)據(jù)不值得用分支換。對(duì)做底層優(yōu)化的工程師來說這類經(jīng)驗(yàn)在編譯器后端、文本編輯器的語法高亮、數(shù)據(jù)清洗工具里都很常見。很多團(tuán)隊(duì)優(yōu)化熱點(diǎn)路徑時(shí)第一個(gè)想到的就是減少內(nèi)存訪問次數(shù)畢竟帶寬在紙面上是最貴的資源。但編譯器優(yōu)化和 CPU 分支預(yù)測(cè)的實(shí)際行為往往比內(nèi)存帶寬更能決定吞吐量。實(shí)測(cè)里有個(gè)容易被忽略的細(xì)節(jié)兩階段方案里內(nèi)層 block convert 仍然向量化成了單個(gè) 16 字節(jié)操作。也就是說把檢測(cè)和轉(zhuǎn)換分開反而讓每一半都能獨(dú)立優(yōu)化到極致——檢測(cè)無分支無存儲(chǔ)轉(zhuǎn)換向量化無分支。各自做到最好合起來比勉強(qiáng)融合更強(qiáng)。目前沒有公開信息說明這個(gè)算法在不同架構(gòu)比如 32 位或 ARM上的表現(xiàn)也沒有部署成本和維護(hù)復(fù)雜度的數(shù)據(jù)。GitHub 分享的主要是一個(gè)優(yōu)化思路當(dāng)你在熱點(diǎn)循環(huán)里糾結(jié)要不要省一次內(nèi)存訪問時(shí)先想想分支會(huì)不會(huì)讓編譯器放棄向量化。這個(gè)取舍的順序比少讀一遍本身更值得記下來。關(guān)于維基框架維基框架關(guān)注企業(yè)應(yīng)用開發(fā)中的長(zhǎng)期維護(hù)問題。在實(shí)際項(xiàng)目中業(yè)務(wù)系統(tǒng)往往同時(shí)涉及權(quán)限、微服務(wù)、接口協(xié)議、部署環(huán)境等復(fù)雜因素因此我們希望提供一套更容易擴(kuò)展和維護(hù)的基礎(chǔ)框架。官網(wǎng)framewiki.comGiteegitee.com/wiki-frameworkGitHubgithub.com/wiki-framework示例項(xiàng)目gitee.com/cdkjframework/framewiki-example 許可證MulanPSL-2.0木蘭寬松許可證第2版