Protocol Buffers が本当に遅いのか実際に確かめてみた

Protocol Buffers で検索すると Protocol Buffersは遅い という MessagePack 作者による2008年の記事が未だに上位に来る。 一方で、Protocol Buffersは遅いのか という反論記事も見つかる。 一体遅いのか速いのかどっちなんだ!!ということで、ベンチマークを取ってみた。

2016年8月現在では、Protocol Buffer の最新バージョンは 3.0.0 であり、MessagePack の C++ バインディングの最新バージョンは 2.0.0 なので、これらのバージョンを使ってベンチマークを取ることにした。

ベンチマーク

元の記事を踏襲して、以下の4つのメッセージを使ってベンチマークを行った。

  • Test1: 2つの符号無し整数
  • Test2: 2つの符号付き整数
  • Test3: 8KBのバイト列
  • Test4: Test1 + Test2 + Test3

Test1 と Test2 は 223 個、Test3 と Test4 は 216 個のメッセージをシリアライズして所要時間を計測し、再びそれをデシリアライズして所要時間を計測した。 外乱の影響を抑えるため、それぞれのワークロードを10回ずつ実行して所要時間の最小値を最終結果とした。

環境:

Test1: 2つの符号無し整数

Serialize Deserialize Size
Protobuf 107 msec 145 msec 32 MB
MessagePack 100 msec 1929 msec 24 MB

シリアライズにかかる時間はほとんど同じだったが、MessagePack のデシリアライズが Protobuf の10倍以上遅い。

Test2: 2つの符号付き整数

Serialize Deserialize Size
Protobuf 112 msec 147 msec 32 MB
MessagePack 102 msec 1954 msec 24 MB

Test1 とほぼ同じ結果になった。 上で挙げた記事では Protobuf の符号付き整数のシリアライズ後のサイズが非常に大きいと書いてあるが、sint を使えば MessagePack と同じサイズになる。 (Protobuf と MessagePack のサイズ差はタグの有無によるもの)

Test3: 8KBのバイト列

Serialize Deserialize Size
Protobuf 162 msec 42 msec 512 MB
MessagePack 121 msec 79 msec 512 MB

バイト列のシリアライズは MessagePack の方が速かった。逆にデシリアライズは Protobuf の方が速い。

Test4: Test1 + Test2 + Test3

Serialize Deserialize Size
Protobuf 165 msec 66 msec 513 MB
MessagePack 123 msec 83 msec 513 MB

Test3 と同じくシリアライズは MessagePack の方が速く、デシリアライズは Protobuf の方が速いという結果になった。

考察

ベンチマークの結果から、バイト列のシリアライズは MessagePack の方が速いが、デシリアライズや整数のシリアライズは Protobuf の方が速いことがわかった。 したがって、2016年の現在においては Protobuf は別に遅くないと思ってよさそう。

ベンチマークプログラム

https://gist.github.com/nojima/005cf04bfa35a1fb971adc43b54abbef