【问题标题】:Handling large amounts of data in C++, need approach在 C++ 中处理大量数据,需要方法
【发布时间】:2014-04-27 19:39:53
【问题描述】:

所以我有一个 CSV 格式的 1GB 文件,我将其转换为 SQLite3 数据库

column1;column2;column3
1212;abcd;20090909
1543;efgh;20120120

除了我有 12 列。现在,我需要读取和排序这些数据并重新格式化输出,但是当我尝试这样做时,似乎我的 RAM 用完了(使用向量)。我从 SQLite 中读取它并将文件的每一行存储在一个结构中,然后将其推回双端队列。就像我说的,当 RAM 使用量接近 2gb 时,我的内存用完了,应用程序崩溃了。我尝试使用 STXXL,但显然它不支持非 POD 类型的向量(因此它必须是 long int、double、char 等),并且我的向量主要由 std::string、一些 boost::date 和一个 double 组成价值。

基本上我需要做的是将所有“行”组合在一起,在特定列中具有相同的值,换句话说,我需要根据一列对数据进行排序,然后使用它。

关于我如何阅读所有内容或至少对其进行排序的任何方法?我会用 SQLite3 来做,但这似乎很耗时。也许我错了。

谢谢。

【问题讨论】:

    标签: c++ sqlite stxxl large-data


    【解决方案1】:

    按要求排序:

    1. 根本不要使用 C++,如果可能的话就使用sort
    2. 如果您热衷于使用数据库以听起来不是真正相关的方式处理不是非常大的 csv 文件,请将所有繁重的工作转移到数据库中,让它担心内存管理。
    3. 如果您必须在 C++ 中执行此操作:
      • 完全跳过 SQLite3 步骤,因为您没有将它用于任何事情。只需将 csv 文件映射到内存中,并构建一个行指针向量。在不移动数据的情况下对 this 进行排序
      • 如果必须将行解析为结构:
        • 不要将字符串列存储为std::string - 这需要额外的非连续分配,这会浪费内存。如果长度是有界的,则首选内联字符数组
        • 选择适合您的值的最小整数大小(例如,uint16_t 适合您的示例第一列值)
        • 注意填充:检查结构的大小,如果它比预期大得多,则重新排序成员或打包它

    【讨论】:

      【解决方案2】:

      如果您想坚持使用 SQLite3 方法,我建议使用列表而不是向量,这样您的操作系统就不需要找到 1GB 或更多的连续内存。

      如果您可以跳过 SQLite3 步骤,我将按照以下方式解决问题:

      1. 编写一个类(例如MyRow),它对数据集中的每一列都有一个字段。
      2. 将文件读入std::list<MyRow>,其中数据集中的每一行都成为MyRow 的实例
      3. 编写一个比较所需列的谓词
      4. 使用 std::list 的排序功能对数据进行排序。

      希望对你有帮助。

      【讨论】:

      【解决方案3】:

      std::string 的开销很大。如果您的struct 每列都包含一个std::string,那么您将在char * 指针、malloc 标题等上浪费大量空间。

      尝试在读取文件时立即解析所有数字字段,并将它们以ints 或任何您需要的形式存储在您的结构中。

      如果您的文件实际上包含很多像您的示例所示的数字字段,我希望它使用 less 比解析后文件大小的内存价值。

      【讨论】:

        【解决方案4】:

        为您的记录创建一个结构。

        记录应该对您需要排序的字段具有“排序”功能。

        将文件作为对象读取并存储到具有随机访问能力的容器中,例如std::vectorstd::array

        对于您要排序的每个字段: 创建一个索引表std::map,使用字段值作为键,记录的索引作为值。

        要按顺序处理字段,请选择您的索引表并遍历索引表。使用值字段(又名索引)从对象容器中获取对象。

        如果记录是固定长度或可以转换为固定长度,您可以将二进制对象写入文件并将文件定位到不同的记录。像上面一样使用索引表,除了使用文件位置而不是索引。

        【讨论】:

        • 我这样做了,但我的 RAM 超过了 2GB。这就是为什么我要求另一种方法,但还是感谢您的回答!
        【解决方案5】:

        感谢您的回答,但我想出了一个非常快速且简单的方法。

        我让 SQLite3 为我完成这项工作,给它这个查询:

        SELECT * FROM my_table ORDER BY key_column ASC
        

        对于一个 800MB 的文件,处理大约需要 70 秒,然后我收到了 C++ 程序中的所有数据,这些数据已经按我希望它们分组的列排序,我一次处理一组,并以我想要的输出格式一次输出一个,使我的 RAM 不会过载。操作的总时间约为 200 秒,我很满意。

        感谢您的宝贵时间。

        【讨论】:

          猜你喜欢
          • 2021-08-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-14
          • 2017-08-24
          • 2011-09-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多