0

可能的重复:
提升精神 QI 缓慢

我目前正在尝试使用 Boost Spirit QI 进行 CSV 数据解析。

我正在使用 1GB CSV 文件运行我的测试。每行看起来像

123|123|\n

该文件大约有60Mio。行。

我稍后想为我知道列的数据类型的任意 CSV 文件生成解析器。所以我首先做了一个测试,使用语法将行解析为整数行(由两个整数组成的结构的向量):

csv = *(int_ >> lit('|') >> int_ >> lit('|'));

在大约 2 秒内解析文件并填充向量。对于我的基准测试,我首先将 CSV 文件加载到内存中的 std::string 中(因此从磁盘加载文件不会影响性能)。

现在我尝试了相同的方法,但使用以下语法将第一列解释为字符串列(解析为由 std::string 和 int 组成的结构的向量):

csv = *(lexeme[*~char_('|')] >> lit('|') >> int_ >> lit('|'));

解析现在需要 12 秒,并且内存消耗正在飙升。我确保我没有交换(swapoff) - 所以这不是瓶颈。我想知道为什么 Spirit QI 中分隔字符串的解析效率如此之低。我的意思是强制转换应该比memcpy解析字符串更昂贵。有没有更好的办法?

更新:分隔字符串显然似乎是性能瓶颈。将行解释为 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