0

重複の可能性:
ブーストスピリット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;
4

0 に答える 0