重複の可能性:
ブーストスピリットQIスロー
現在、CSV データの解析に Boost Spirit QI を使用する実験を行っています。
1GB の CSV ファイルを使用してテストを実行しています。各行は次のようになります
123|123|\n
ファイルには約60Mioがあります。行。
後で、列のデータ型がわかっている任意の CSV ファイルのパーサーを生成したいと考えています。そこで、最初に文法を使用して、行を整数行 (2 つの int で構成される構造体のベクトル) として解析するテストを行いました。
csv = *(int_ >> lit('|') >> int_ >> lit('|'));
約 2 秒でファイルが解析され、ベクターが埋められます。私のベンチマークでは、最初に CSV ファイルをメモリ内の std::string にロードしました (そのため、ディスクからファイルをロードしてもパフォーマンスには影響しません)。
今、私は同じことを試みましたが、文法を使用して最初の列を文字列列として解釈しました (std::string と int で構成される構造体のベクトルに解析します):
csv = *(lexeme[*~char_('|')] >> lit('|') >> int_ >> lit('|'));
解析には 12 秒かかり、メモリ消費量は急増しています。スワップ (swapoff) していないことを確認したので、これはボトルネックではありません。区切られた文字列の解析が Spirit QI で効率が悪いのはなぜだろうと思っていました。memcpy
つまり、キャストは、解析された文字列を ing するよりもコストがかかるはずです。より良い方法はありますか?
更新:区切り文字列は明らかにパフォーマンスのボトルネックのようです。行を double および int として文法とともに解釈するとcsv = *(double_ >> lit('|') >> int_ >> lit('|'));
、ファイルも 2 秒で解析されます。
更新 2 (コード):
namespace test
{
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
struct row
{
std::string a;
int b;
};
}
BOOST_FUSION_ADAPT_STRUCT(
test::row,
(std::string, a)
(int, b)
)
namespace test
{
template <typename Iterator>
struct row_parser : qi::grammar<Iterator, std::vector<row>(), ascii::space_type>
{
row_parser() : row_parser::base_type(start)
{
using qi::int_;
using qi::lit;
using qi::double_;
using qi::lexeme;
using ascii::char_;
start = *(lexeme[*~char_('|')] >> lit('|') >> int_ >> lit('|'));
}
qi::rule<Iterator, std::vector<row>(), ascii::space_type> start;
};
}
using boost::spirit::ascii::space;
typedef std::string::const_iterator iterator_type;
typedef test::row_parser<iterator_type> row_parser;
std::vector<test::row> v;
row_parser g;
std::string str;
string dataString(buffer, fileSize); // buffer contains the CSV file contents, fileSize is its size
auto startBoostParseTime = chrono::high_resolution_clock::now();
string::const_iterator iter = dataString.begin();
string::const_iterator end = dataString.end();
phrase_parse(iter, end, g, space, v);
auto endBoostParseTime = chrono::high_resolution_clock::now();
auto boostParseTime = endBoostParseTime - startBoosParseTime ;
cout << "Boost Parsing time: " << boostParseTime.count()<< " result size "<< v.size() <<endl;