Post on 15-Jun-2015
description
PHP meets MessagePack,
KLab株式会社 研究開発部 竹井英行
2009年11月13日
and I meets PHP Extension.
自己紹介•今年4月入社の新卒、竹井です
• 主にモバイル向けSNSやCMSの開発してます
• プライベートではUSBガジェットやロボット、プロダクトなどのハードウェアを開発してます
AGENDA
• MessagePackの紹介
• 仕様
• 特徴
• PHP Extensionを作ろう
• 概要
• PHP<‒>Cでの値の受け渡し方
MessagePackとは•古橋貞之(id:viver)さん考案
• 性能を重視したバイナリベースで高速な シリアライズ形式
• JSON : テキストベースのシリアライズ形式
• MessagePack = 速いJSON
• http://msgpack.sourceforge.jp
MessagePackとKLabの関係
• Kラボの稲田がPythonライブラリを開発
• でMessagePackを使用
• Erlang版も開発中
• PHP版はまだない!→ここは私が!!
MessagePackの仕様
•整数, Boolean, 文字列, 配列, 連想配列, nilをバイト列にシリアライズ
• データ型, データ(整数やfloat, double)
• データ型, 長さ, データ, データ,… (Raw, Array, Map)
• ビッグエンディアン
MessagePackとJSON
• [1,2,3]という配列のシリアライズ後の表現を比較
• json: [1,2,3]←テキスト
• 5B 31 2C 32 2C 33 5D (LEN:7)• msgpack: 93 01 02 03 (LEN:4)
一例• Positive FixNum(0~127) : 1byte
• uint 8 : 2bytes
0XXX XXXX
1100 1101 XXXX XXXX
• fix raw : (N+1)bytes [000XXXXX(=N)<32]
… N bytes101X XXXX
MessagePackの特徴
•シリアライズ/デシリアライズが高速
• シリアライズされたデータサイズが小さい
• フォーマット定義(IDL)が不要
• ストリーム処理ができる
シリアライズ/デシリアライズが高速
• [0, 1, 2, 3, ..., 2^24]という整数の配列
対象 形式 シリアライズ デシリアライズ
整数の配列msgpack 0.701秒 0.484秒json 8.11秒 5.83秒
文字列の配列msgpack 0.829秒 0.00581秒json 7.18秒 8.87秒
• ["", "a", "aa", ..., "a"*2^15]という文字列の配列
• MessagePackとJSONのベンチマーク*を比較
*:参考文献 http://d.hatena.ne.jp/viver/20080816/p1
シリアライズされた
•MessagePackはJSONと比べて60%程度の小ささ
• 32bitsの整数を保存する場合
• json : 最大10bytes (2^32で10桁)
• msgpack : 最大5bytes (データ型1+データ4)
対象 形式 サイズ
整数の配列msgpack 79.9MBjson 133MB
データサイズが小さい
フォーマット定義(IDL)が不要
• Protocol Buffers : Googleが開発した バイナリエンコード手法
• IDL : フォーマットを記述するための言語
• Protocol Buffers はIDLで静的に型付け
• MessagePackは動的型付け(自己記述性)
• 必要になったときに静的型に変換する
参考文献 http://d.hatena.ne.jp/viver/20081116/p1
ストリーム処理ができる•流れてくるデータを順次ストリーム処理
することができる
• データ型, (長さ,)データで保存される
• メッセージとメッセージの切れ目を 知ることができる
• デシリアライザにデータを投げていく だけでメッセージを1つずつ取り出せる
アプローチ
• PEAR のように PHP でクラスライブラリ
を作る(ペアる)
• PECL のように PHP 自体を拡張する モジュールを書く(ピクる)
PHPで汎用的なライブラリを作成する方法は2つ
なぜ ピクるのか?•過去に C で書かれた既存のライブラリを
流用できる
• MessagePackにはすでにCのライブラリがある!!
• PEAR のように PHP で書いたコードと 比べると高速に動作する
とても簡単だったPHP Extensionの作り方
• phpのソースをダウンロード・展開する
• extディレクトリに移動
• スケルトンを作成する (./ext_skel --extname=xx)
• $phpize
• Cのコードを書く←がんばりどころ!
• $./configure そして $make
• modules/*.soのできあがり congratulation!!
いろいろありますがつまり!
• phpからCの関数が呼べます!• 詳しくは「DSAS開発者の部屋:PHP Extension を作ろう」シリーズ参照
http://dsas.blog.klab.org/archives/50777398.html
• 値を渡す/返すを試みよう。……ん?
• PHP : 動的型付け,C : 静的型付け
• PHPのデータ表現(zend.h)を見れば一目瞭然!
typedef union _zvalue_value { long lval; /* long value */ double dval; /* double value */ struct { char *val; int len; } str; HashTable *ht; /* hash table value */ zend_object obj;} zvalue_value;
struct _zval_struct { zvalue_value value; /* value */ zend_uchar type; /* active type */ zend_uchar is_ref; zend_ushort refcount;};
php-x.x.x/Zend/zend.h より…
といっても
•値の受け渡しするための便利なマクロがたくさん用意されています
値を受け取る方法• ZEND_NUM_ARGS … 引数の数を取得する
• TSRMLS_CC … スレッドセーフなことを保証PHP_FUNCTION(example2){ char *str; int str_len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { return; } printf("%s\n", str);}
返値を返す方法• zval型のreturn_valueに値をセットする
• 最初に引数で渡された zval の参照で値を返している
#define ZVAL_LONG(z, l) { \ Z_TYPE_P(z) = IS_LONG; \ Z_LVAL_P(z) = l; \}
#define RETURN_LONG(l) { RETVAL_LONG(l); return; }
#define RETVAL_LONG(l) ZVAL_LONG(return_value, l)
PHP Extension作りの参考資料
• php-x.x.x/ext ディレクトリにPECLのPHPエクステがたくさんあります
• msgpackのPHPエクステもJSONのものをリスペクトした形になっています
• Cでの配列と連想配列の判定など
• 近日中にmsgpack本家登録&PECL登録予定!乞うご期待!