Pythonのpickle.dumpに3番目の引数がある話

cPickle.dump(obj, f, -1)みたいな使い方を見て、なんだこの-1?と思ったので調べてみた。簡潔に言えば、これはフォーマットの指定で、指定しなかったときは後方互換性のために初期のASCII形式での保存がおこなわれる。-1ってのは最新のを使えという意味で、今ならバージョン2ということになる。

There are currently 3 different protocols which can be used for pickling.

  • Protocol version 0 is the original ASCII protocol and is backwards compatible with earlier versions of Python.
  • Protocol version 1 is the old binary format which is also compatible with earlier versions of Python.
  • Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes.

http://docs.python.org/library/pickle.html

で、気になるのはファイルサイズとか速度とかだよね。

計測方法

Numpyのndarrayで1000x1000のサイズの0〜1の乱数が入った行列を作り、それを文字列にシリアライズしてサイズと時間を計測した。サイズは文字列の長さ、時間はipythonの%timeitで適当な回数繰り返して計測した。

時間

まあざっくり100倍違いますね。

%timeit s = cPickle.dumps(m)
1 loops, best of 3: 1.14 s per loop

%timeit s = cPickle.dumps(m, 1)
100 loops, best of 3: 18.4 ms per loop

%timeit s = cPickle.dumps(m, 2)
100 loops, best of 3: 18.4 ms per loop

サイズ

こちらの差は3倍弱。

len(cPickle.dumps(m))
22217167

len(cPickle.dumps(m, 1))
8000141

len(cPickle.dumps(m, 2))
8000136

まとめ

version 1と2の違いは対象がndarrayだとよくわからないけど、少なくともversion 0を使い続ける明確な理由がないなら新しいバージョンを使った方がよさそう。

おまけ

Cで書かれていないpickleの方を使った場合、version 0では速度に大した差が出ないが、1以降なら2〜3倍遅い。

%timeit s = pickle.dumps(m)
1 loops, best of 3: 1.16 s per loop

%timeit s = pickle.dumps(m, 1)
10 loops, best of 3: 42.3 ms per loop

%timeit s = pickle.dumps(m, 2)
10 loops, best of 3: 42.1 ms per loop