【问题标题】:Surprising performance degradation with std::vector and std::stringstd::vector 和 std::string 令人惊讶的性能下降
【发布时间】:2020-09-17 04:53:09
【问题描述】:

我正在通过以下方式处理非常大的文本文件:

class Loader{
    template<class READER>
    bool loadFile(READER &reader){
        /* for each line of the input file */ {
            processLine_(line);
        }
    }

    bool processLine_(std::string_view line){
        std::vector<std::string> set; // <-- here
        std::string buffer;           // <-- here

        // I can not do set.reserve(),
        // because I have no idea how much items I will put.

        // do something...
    }

    void printResult(){
        // print aggregated result
    }
}

处理 143,000,000 条记录大约需要 68 分钟。

所以我决定对几个std::array 缓冲区进行一些非常棘手的优化。结果大约是 62 分钟。
但是代码变得非常不可读,所以我决定不在生产中使用它们。

然后我决定做部分优化,例如

class Loader{
    template<class READER>
    bool loadFile(READER &reader);

    std::vector<std::string> set; // <-- here
    std::string buffer;           // <-- here

    bool processLine_(std::string_view line){
        set.clear();

        // do something...
    }

    void printResult();
}

我希望这会减少来自 bufferset 向量的 malloc / free (new[] / delete[]) 操作。我意识到set 向量中的字符串仍然动态分配内存。

但是结果到了 83 分钟。

请注意,除了将setbuffer 移动到“类”级别之外,我不会更改任何内容。我只在processLine_ 方法中使用它们。

这是为什么呢? 参考地点?

我想到的唯一解释是一些字符串足够小并适合 SSO,但这听起来不太可能。

将 clang 与 -O3 一起使用

【问题讨论】:

  • 在开始处理之前是否将文件的每条记录都加载到内存中?您可能会用完 RAM,而您的操作系统决定使用交换空间?如果你想减少重新分配,你可以使用某种启发式(文件大小)来预测你需要的向量元素的近似数量。数据库会比平面文件更好吗?
  • 你对setbuffer末尾的processLine_的内容或内容做了什么吗?
  • @JohnFilleau 是的,但我认为这并不重要。它读取文件,然后为 txt 文件的每一行调用此函数processLine_processLine_ 在这两种情况下都是一样的,它做一些类似聚合的事情。我有另一种显示结果的方法。
  • @FrançoisAndrieux 不,我不会在 processLine_ 方法之外使用它们。所有代码不变
  • 我们甚至看不到您描述的代码。尝试使用性能分析器。

标签: c++ string vector


【解决方案1】:

我做了profile,发现大部分时间都花在了第三方C库中。

我以为这个库很快,但事实并非如此。

我仍然对减速感到困惑,但即使我对其进行优化,也不会产生如此大的影响。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    • 2015-05-13
    • 2017-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    相关资源
    最近更新 更多