2009年07月13日

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() へ対応しようと思います。


@methane

klab_gijutsu2 at 15:58│Comments(1)TrackBack(1)Python 

トラックバックURL

この記事へのトラックバック

1. [Python]ベンチマーク方法が・・・  [ name-3333’s memo (個人用メモなんで間違いがあるかも知れません) ]   2009年07月31日 22:02
DSAS開発者の部屋 MessagePackのPython Bindingをリリースしました より http://dsas.blog.klab.org/archives/51456004.html ベンチマーク方法がちょっと。MessagePackがバイナリ形式なんやからpickleもバイナリ指定して比較しないと。 というだけではなんなんでやってみた

この記事へのコメント

1. Posted by taksatou   2009年11月30日 02:59
はじめまして。

このエントリーを参考にしてMessagePackのPHP Extensionを作ってみました。
もしよければチェックしてみてください。

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント
最新トラックバック
Archives