MessagePackのPython Bindingをリリースしました
MessagePack とは、古橋(id:viver)さんが開発された高速・高効率なバイナリシリアライズフォーマットです。詳しくは 古橋さんの日記 やプロジェクトサイト を見てください。
PythonからMessagePackフォーマットでSerialize/DeserializeするためのPythonパッケージを作ったので、取得方法と使い方について簡単に紹介します。
1. インストール
msgpackという名前でPython Package Index (PyPI)に登録してあります。 <http://pypi.python.org/pypi/msgpack/>
setuptoolsをインストールしている環境では、
$ easy_install msgpack
でインストールすることができます。
Windowsでインストールする場合は、PyPIのパッケージサイト からインストーラをダウンロードしてインストールするのがお手軽です。
2. シリアライズ
まず、msgpackパッケージをimportします。
>>> import msgpack >>> help(msgpack) # docstring を読む
一つのオブジェクトをシリアライズするには、 msgpack.packb() を利用するのが簡単です。
>>> msgpack.packb([1,2,3]) '\x93\x01\x02\x03'
連続してシリアライズする場合、 msgpack.Packer オブジェクトを利用するとオーバーヘッドが少なくなります。
>>> packer = msgpack.Packer() >>> packer.pack([1,2,3]) '\x93\x01\x02\x03' >>> packer.pack([4,5,6]) '\x93\x04\x05\x06'
3. デシリアライズ
msgpack.unpackb() を利用すると、1オブジェクト分のシリアライズされたデータをデシリアライズできます。
>>> msgpack.unpackb(b'\x93\x01\x02\x03') [1, 2, 3]
ストリームからデシリアライズする場合、 msgpack.Unpacker オブジェクトを利用することで、連続したデシリアライズができたり、オブジェクトの境界が判らない場合に対応できます。
>>> unpacker = msgpack.Unpacker() >>> buf = b'\x93\x01\x02\x03' * 5 >>> len(buf) 20 >>> unpacker.feed(buf[:9]) >>> for o in unpacker: ... print o ... [1, 2, 3] [1, 2, 3] >>> unpacker.feed(buf[9:]) >>> for o in unpacker: ... print o ... [1, 2, 3] [1, 2, 3] [1, 2, 3]
4. ベンチマーク
テストコード:
#!/usr/bin/env python # coding: utf-8 from msgpack import packs, unpacks from cPickle import dumps, loads import simplejson as json from time import time BENCH_NUM = 10 def bench(func, num=BENCH_NUM): start = time() for i in xrange(BENCH_NUM): func() end = time() print "%-12s %4.3f[ms]" % (func.__name__, (end-start)*1000/BENCH_NUM) def setup_int(): global a, a_pickle, a_mpack, a_json a = range(1024) * 2**10 a_pickle = dumps(a) a_json = json.dumps(a) a_mpack = packs(a) def setup_str(): global a, a_pickle, a_mpack, a_json a = ['a'*(i % 4096) for i in xrange(2**14)] a_pickle = dumps(a) a_json = json.dumps(a) a_mpack = packs(a) def pickle_dump(): dumps(a) def pickle_load(): loads(a_pickle) def json_dump(): json.dumps(a) def json_load(): json.loads(a_json) def mpack_pack(): packs(a) def mpack_unpack(): unpacks(a_mpack) targets = [ pickle_dump, pickle_load, json_dump, json_load, mpack_pack, mpack_unpack] import gc gc.disable() bytes_suffix = "[bytes]" print "== Integer ==" setup_int() print "= Size =" print "pickle:", len(a_pickle), bytes_suffix print "json: ", len(a_json), bytes_suffix print "mpack: ", len(a_mpack), bytes_suffix for t in targets: bench(t) print "== String ==" setup_str() print "= Size =" print "pickle:", len(a_pickle), bytes_suffix print "json: ", len(a_json), bytes_suffix print "mpack: ", len(a_mpack), bytes_suffix for t in targets: bench(t)
結果:
== Integer == = Size = pickle: 6203398 [bytes] json: 5154816 [bytes] mpack: 2752517 [bytes] pickle_dump 248.640[ms] pickle_load 360.288[ms] json_dump 255.601[ms] json_load 136.922[ms] mpack_pack 51.383[ms] mpack_unpack 26.851[ms] == String == = Size = pickle: 33731696 [bytes] json: 33611776 [bytes] mpack: 33595139 [bytes] pickle_dump 182.324[ms] pickle_load 141.639[ms] json_dump 126.675[ms] json_load 93.945[ms] mpack_pack 66.833[ms] mpack_unpack 34.953[ms]
pickleやjsonを圧倒していますが、まだまだ改善の余地がありそうです。 とくにpackはunpackと違って大量のPythonオブジェクトを生成する必要があるわけではないのに、unpackよりも時間がかかってしまっています。
5. その他
ここでは紹介していない、simplejsonやpickleモジュールに似せたAPIもあります。pickleやjsonからmsgpackへ移行するときはパッケージの中を探してみて下さい。
ただし、現在のmsgpackはバイト列・整数・浮動小数点数・シーケンス型・辞書型にしか対応できていません。simplejsonは dumps() に defalut() 関数を、 loads() に object_hook() 関数を用意することでユーザーが定義したクラスのシリアライズ・デシリアライズができます。0.2 では同じような default() とobject_hook() へ対応しようと思います。
トラックバックURL
この記事へのトラックバック
この記事へのコメント
このエントリーを参考にしてMessagePackのPHP Extensionを作ってみました。
もしよければチェックしてみてください。