2013/05/28

Recent entries from same category

  1. RapidJSON や simdjson よりも速いC言語から使えるJSONライブラリ「yyjson」
  2. コメントも扱える高機能な C++ 向け JSON パーサ「jsoncpp」
  3. C++ で flask ライクなウェブサーバ「clask」書いた。
  4. C++ 用 SQLite3 ORM 「sqlite_orm」が便利。
  5. zsh で PATH に相対パスを含んだ場合にコマンドが補完できないのは意図的かどうか。

なんびとたりとも俺の前は走らせねぇ
ガチバトルです。
rapidjson - A fast JSON parser/generator for C++ with both SAX/DOM style API - Google Project Hosting

Rapidjson is an attempt to create the fastest JSON parser and generator. Small but complete. Support...

https://code.google.com/p/rapidjson/
fastest をうたうとは度胸があるなーと思いながら、半信半疑で試してみました。
rapidjson も picojson 同様に、ヘッダファイルだけあればコンパイル出来る C++ 向け JSON パーサ(およびシリアライザ)です。
まずは rapidjson を使ったコード。
#include <rapidjson/document.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <time.h>

int
main(int argc, char* argv[]) {
  clock_t t;
  t = clock();
  for (int n = 0; n < 1000; n++) {
    std::stringstream ss;
    std::ifstream f;
    f.open("foo.json", std::ios::binary);
    ss << f.rdbuf();
    f.close();

    rapidjson::Document doc;  
    if (doc.Parse<0>(ss.str().c_str()).HasParseError()) {
      std::cerr << "parse error" << std::endl;
      return 1;
    }

    rapidjson::Value& entries = doc["entries"];
    int i, l = entries.Size();
    for (i = 0; i < l; i++) {
      std::cerr << entries[rapidjson::SizeType(i)]["title"].GetString() << std::endl;
    }
  }
  std::cout << "score: " << clock() - t << std::endl;
  return 0;
}
そして picojson を使ったコード #include <picojson.h>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <time.h>

int
main(int argc, char* argv[]) {
  clock_t t;
  t = clock();
  for (int n = 0; n < 1000; n++) {
    std::stringstream ss;
    std::ifstream f;
    f.open("foo.json", std::ios::binary);
    ss << f.rdbuf();
    f.close();

    picojson::value v; ss >> v;
    picojson::array a = v.get<picojson::object>()["entries"].get<picojson::array>();
    int i, l = a.size();
    for (i = 0; i < l; i++) {
      std::cerr << a[i].get<picojson::object>()["title"].to_str() << std::endl;
    }
  }
  std::cout << "score: " << clock() - t << std::endl;
  return 0;
}
picojson については、std::for_each を使っても見たけど結局自前ループで回した方が速い結果になりました。

コンパイルは両者とも g++ -std=c++11 -O2 foo.cxx でやりました。
読み込んでる JSON はこれを使いました。ウチのサイトの JSON 形式のフィードです。やってる内容は
  • ファイルを読み込む
  • パースする
  • entries の一覧を取る
  • 各 title の内容を標準エラーに出力する
これを1000回実行します。標準エラーは捨てながら計測しました。

結果は以下の通り。 rapidjson score: 3559
picojson score: 7961
こうなりました。picojson と比べて rapidjson がほぼ2倍速いという結果になりました。速い理由をソースを見ながら調べてみましたが、rapidjson は STL を使わず、自前で DOM ライクな API を提供しています。また std::string なども使いません。これによってオーバーヘッドを最小限に抑えているのだと思います。
もちろん、picojson の STL フレンドリも僕は好きですし、他の C++ ライブラリと連携する際にも便利です。

Performance - rapidjson - Compares some performance benchmark results of rapidjson 0.1 and other parsers. Also gives some analysis. - A fast JSON parser/generator for C++ with both SAX/DOM style API - Google Project Hosting

Why rapidjson is fast? rapidjson has made use of several techniques to achieve high performance. C++...

https://code.google.com/p/rapidjson/wiki/Performance
それどころか、このスコア表を見ると picojson のスコアは素晴らしいレベルだと分かりました。
唯一難点として rapidjson は確かに速いのですが、パースエラー詳細に取る方法が分かりませんでした。(あるのかもしれません。知ってる人いたら教えて下さい)

という事で、これからも picojson 使って行こうと思います。
Posted at by