Looks Go To Me

golang をゆったり学びます。

golang regexp の速度について

最近 regexp 系をいろいろさわってました。 golangregexp が c, ruby, perl などと比べて遅いというのはググったらいろいろ情報出てくるんですねー。

さて、regexp 処理がメインの perl モジュールを go に移植したんですが、チューニングしても 3倍以上の速度差がありました。(愚直に移植しただけだと10倍以上の差異)

pprof みると、

    46.11s 33.43% 33.43%     99.23s 71.95%  regexp.(*machine).tryBacktrack
    14.47s 10.49% 43.93%     14.47s 10.49%  regexp.(*bitState).push
    12.89s  9.35% 53.27%     15.67s 11.36%  unicode.SimpleFold
    11.57s  8.39% 61.66%     11.57s  8.39%  regexp.(*inputBytes).step
     9.44s  6.85% 68.51%     25.11s 18.21%  regexp/syntax.(*Inst).MatchRunePos
     3.80s  2.76% 71.26%    109.07s 79.09%  regexp.(*machine).backtrack
     3.25s  2.36% 73.62%     28.36s 20.56%  regexp/syntax.(*Inst).MatchRune

こんな感じで上位に居て、tryBacktrack かー、、、これ、正規表現を綺麗に書くとかで回避できる感じもあるけど、無理な場合もあるなーとか、結構サックり改善できそうもなかったです。

ちなみに、最初こんなコードを書いてたんですが

func (f Filler) unquote(tag []byte) []byte {
    newTag := f.compileMultiLine(`['"](.*)['"]`).FindSubmatch(tag)
    if cap(newTag) == 2 {
        return newTag[1]
    }
    return tag
}

こうなおしたら

func (f Filler) unquote(tag []byte) []byte {
    return bytes.Trim(tag, `'"`)
}

100倍早くなりました。

いまのところ、regexp を回避していくことが速度改善の秘訣のようです。

あと、pprof は Mac だとできない。これ、罠。