お世話になっております。
しゃまとんです。

ちょっとしたお知らせです。
タイトルの通りなんですが、golangで使えるMessagePackのシリアライザを作りました。
(🎉個人的にはパンパカパーン🎉)

まず、MessagePackとはデータのシリアライズフォーマットの1つで効率の良い形式として知られています。よくJSONと比較・検証されて使われていることが多いですね。
現在は多くの言語で使えるようになっており、言語間で何かデータのやり取りをするときに候補の1つになっています。

公式にもある通り、JSONよりも軽量で速いのが特徴です。

もちろんGo言語でもMessagePackが扱えるパッケージがすでにいくつか存在しており、使いたければ使える状況になっています。自分自身も使っていたのですが、とあるきっかけからpackageを覗いてみたところ、なんとなくもう少し速くできそうかなぁ…と思いました。

で、簡単な検証用ベンチマークコードを書いてみたところ、速くなりそうかなぁ…ということで書き始めたのが最初でした。コードを書き換えてはベンチマークを確認して…実装して…を繰り返しすすめていき、現在(2018.09時点)v1.0としてリリースできました。

エンドポイントの名称は迷ったんですが、いろいろ考えてEncode / Decodeにしました。
呼び出しはこんな感じで。

package main
     
import (
    "github.com/shamaton/msgpack"
)

func main() {
    type Struct struct {
        String string
    }
    v := Struct{String: "msgpack"}
    
    d, err := msgpack.Encode(v)
    if err != nil {
        panic(err)
    }
    r := Struct{}
    err = msgpack.Decode(d, &r)
    if err != nil {
        panic(err)
    }
}

単純に使うだけならEncode/Decodeを呼び出すだけです!
引数は標準のパッケージencoding/jsonと同じ形にしてます。(置き換えが容易かも…!)

で、肝心のパフォーマンスですが、まずはシリアライズ。
自分が知っている範囲で他のMessagePackやJSON等の別フォーマットと比較してみます。ベンチマークはおそらくユーザーが呼び出すであろうエンドポイントでとってみました。

$ go test -bench CompareEncode -benchmem
goos: darwin
goarch: amd64
pkg: github.com/shamaton/msgpack_bench
BenchmarkCompareEncodeShamaton-4             1000000          1255 ns/op         320 B/op          3 allocs/op
BenchmarkCompareEncodeVmihailenco-4           300000          4645 ns/op         968 B/op         14 allocs/op
BenchmarkCompareEncodeArrayShamaton-4        1000000          1110 ns/op         256 B/op          3 allocs/op
BenchmarkCompareEncodeArrayVmihailenco-4      300000          4387 ns/op         968 B/op         14 allocs/op
BenchmarkCompareEncodeUgorji-4               1000000          1921 ns/op         986 B/op         11 allocs/op
BenchmarkCompareEncodeZeroformatter-4        1000000          1890 ns/op         744 B/op         13 allocs/op
BenchmarkCompareEncodeJson-4                  500000          3428 ns/op        1224 B/op         16 allocs/op
BenchmarkCompareEncodeGob-4                   200000         11537 ns/op        2824 B/op         50 allocs/op
BenchmarkCompareEncodeProtocolBuffer-4        500000          2338 ns/op         792 B/op         29 allocs/op
PASS
ok      github.com/shamaton/msgpack_bench   14.481s

Shamatonとついているものが今回リリースしたものになります。ArrayShamatonというのはMessagePackのフォーマットが軽量なパターンを採用しているものです(UnityではMessagePack-CSharpでおなじみですね?)。今回のケースでは通常のEncodeでも他のパッケージよりも性能よく動作させられたっぽいです。

次にデシリアライズです。

$ go test -bench CompareDecode -benchmem
goos: darwin
goarch: amd64
pkg: github.com/shamaton/msgpack_bench
BenchmarkCompareDecodeShamaton-4             1000000          1393 ns/op         512 B/op          6 allocs/op
BenchmarkCompareDecodeVmihailenco-4           300000          5393 ns/op        1056 B/op         33 allocs/op
BenchmarkCompareDecodeArrayShamaton-4        2000000           990 ns/op         512 B/op          6 allocs/op
BenchmarkCompareDecodeArrayVmihailenco-4      300000          4397 ns/op         992 B/op         22 allocs/op
BenchmarkCompareDecodeUgorji-4                500000          2587 ns/op         845 B/op         12 allocs/op
BenchmarkCompareDecodeZeroformatter-4        1000000          2350 ns/op         976 B/op         29 allocs/op
BenchmarkCompareDecodeJson-4                  200000          8904 ns/op        1216 B/op         43 allocs/op
BenchmarkCompareDecodeGob-4                    50000         34805 ns/op       10172 B/op        275 allocs/op
BenchmarkCompareDecodeProtocolBuffer-4       1000000          1759 ns/op         656 B/op         19 allocs/op
PASS
ok      github.com/shamaton/msgpack_bench   16.946s

こちらも性能良く動作させられたっぽいです。ただProtocol Bufferはデータの形次第でパフォーマンス良くなることがありました(struct onlyな構成など)。まぁprotoファイルとかを準備しないといけないので、その点よいかなーと。

結果を見る感じだとArray呼び出しがパフォーマンスがやはり良いので、使えるならAsArrayを使うのが良さそうかなと思います。ベンチマークですが、こちらにコードがあるので何かあれば教えてください。

ということで、単純な呼び出しでMessagePack系では割と速いシリアライザを作ることが出来ました。よかったよかった。それと今回の実装でzeroformatter側にも反映できそうなところもわかったので、対応できればなーと思っています。

あと余談ですが、タグでシリアライズ対象の設定ができたりとか、拡張エンコード・デコードにも対応させたりもしてます。(この辺はREADMEとかExampleに書く予定です)

よかったら使ってみてください!
以上です。