« 2008年05月 | メイン | 2008年07月 »
2008年06月27日
C++ で自動型変換
C++ の拡張ライブラリである boost には、lexical_cast というライブラリがあって、iostream への入出力ができる型ならなんでも文字列化 (その逆も) できるので、とても便利です。でも、lexical_cast は、int → long のような変換の場合にも iostream を使った変換をしてしまうので、汎用のリフレクションコードを書こうとすると、そのままでは使いにくいです (オーバーヘッドが大きすぎる)。というわけで、変換前後の型に応じて、static_cast と lexical_cast を自動的に切り替えるようなキャスト関数を作ってみました。こんな感じで使います。
// calls lexical_cast<int>(123) int i = intelligent_cast<int>("123"); // calls static_cast<long>(123) long l = intelligent_cast<int>(123); // calls std::string(const char*) std::string s = intelligent_cast<std::string>("abc");
これで、不用意に数値型間や std::string → std::string のような変換 (コピー) が必要になる場合でも、速度の低下を心配する必要がなくなりました。
ライブラリのコードは以下のような感じ。boost におんぶにだっこなので簡単です (std::string については、実用上の観点から専用コードを追加しています) 。最新版は CodeRepos (/lang/cplusplus/reflection) においてあるので、バグ等ありましたら、指摘もしくは修正いただければ幸いです。
投稿者 kazuho : 2008年06月27日 17:22 | トラックバック (0)
2008年06月25日
なんとなくリフレクション in C++
C++ はとてもいい言語なのですが、リフレクションがありません。昨夜、1年ぶりくらいに C++ でリフレクションしたい熱に感染したのですが、ちょっとググった範囲では良いものが見つからなかったので、作ってみました (単に作りたかっただけという説も)。こんな感じで使います。
#include "reflection.hpp" struct Foo { int i; std::string s; }; // リフレクション情報を定義 namespace reflection { template <> struct def<Foo> : public def_base<Foo> { def() { REFLECTION(i); REFLECTION(s); } }; }; // リフレクションを通してデータを読み込み // 変数が見つからない場合は reflection::name_not_found_error が、 // キャストできない場合は std::bad_cast 例外が送出されます int t = reflection::get<int>(f, "i"); cout << "i=" << t << endl; // リフレクションを通してデータを書き込み reflection::set(f, "s", string("hello world")); // リフレクション情報を iterate して表示 for (reflection::def<Foo>::const_iterator i = reflection::def<Foo>::map.begin(); i != reflection::def<Foo>::map.end(); ++i) cout << i->first << " = " << i->second->get<std::string>(f) <<endl;
このリフレクションライブラリの特徴は、以下のようなものになります。
投稿者 kazuho : 2008年06月25日 08:34 | トラックバック (0)
2008年06月20日
MySQL の ORDER BY を高速化
Pathtraq の拡張にむけて、いろいろ技術的な可能性を調査していると、MySQL の ORDER BY に負荷がかかっていることが分かりました。他にもボトルネックはあるのですが、ここは比較的最適化しやすそうだったので、試しに書いてみました。
やっていることは、ソートルーチンのベタな最適化です。ORDER BY 句によって悪名高き filesort が実行される場合に、最大30%〜50%ほど高速に動作するようになりました。ただ、自分が書く類いのクエリだと、本質的には top n sort を実装すべきなので、どうしたものかと思っています。現状、x86-64 向けに書いているので、RISC だと確実に落ちると思いますが、at your own risk で試したい方はどうぞ。
投稿者 kazuho : 2008年06月20日 15:46 | コメント (1) | トラックバック (0)
2008年06月12日
MySQL (InnoDB) に直接アクセスしてタイムライン処理を高速化する話
フレンド・タイムライン処理の原理と実践 の続きです。
先のエントリでは、プルモデルの速度が当初予測していたよりも遅かった (というより SQL レイヤでのオーバーヘッドが大きそうだった) ので、MySQL Internals メーリングリストで質問したりしながら、C++ で直接 InnoDB にアクセスするようなコードを書いてみました。
タイムライン/秒 | |
---|---|
SQL | 56.7 |
ストアドプロシージャ | 136 |
C++ での直接アクセス |
そしたら、10倍以上高速に! ベンチマークを perl ベースのものから mysqlslap に変えたのですが、プッシュモデルの 2/3 の速度が出ています。これなら、データサイズが約 1/10 になることを考えると、メモリの代わりに CPU に投資するほうが良い、という判断も非常に現実味を帯びてきます。また、最近のクアッドコアな CPU を使えば 10,000 タイムライン/秒クラスも夢じゃないでしょうから、memcached による支援の必要もないのかもしれません。
続きを読む "MySQL (InnoDB) に直接アクセスしてタイムライン処理を高速化する話"
投稿者 kazuho : 2008年06月12日 17:12 | コメント (1) | トラックバック (0)
2008年06月09日
フレンド・タイムライン処理の原理と実践
MySQL (InnoDB) に直接アクセスしてタイムライン処理を高速化する話に続きます。
Twitter が注目されるようになって久しい今日この頃ですが、友人の投稿を時系列に並べて表示する、というのは、Twitter に限らず Mixi の「マイミクシィ最新日記」やはてなブックマークの「お気に入り」等、ソーシャルなウェブサービスにおいては一般的な手法です。ですが、この処理 (以下「フレンド・タイムライン」と呼ぶ) は、一見簡単そうに見えて、実装には様々な困難が伴います。本記事では、「フレンド・タイムライン」を実現する、プッシュ型とプル型の二種類の手法について、その原理的な特徴と問題、および実践的なテクニックについて説明したいと思います。
なお、以下では基本的に SQL を用いて話を進めて行きますが、原理的な部分は、どのようなストレージを使おうと、あるいはスケールアウトしようがしまいが、変わらないと思います。
1. プッシュ型
投稿者 kazuho : 2008年06月09日 14:06 | コメント (8) | トラックバック (6)
MySQL のクエリ最適化における、もうひとつの検証方法
EXPLAIN を使用して MySQL の SQL を最適化するというのは、良く知られた手法だと思います。しかし、EXPLAIN の返す結果が、かならずしもアテになるわけではありません。たとえば、以下のような EXPLAIN を見て、このクエリが最適かどうか、判断ができるでしょうか。私には分かりません。
続きを読む "MySQL のクエリ最適化における、もうひとつの検証方法"
投稿者 kazuho : 2008年06月09日 11:38 | トラックバック (0)