【问题标题】:Read a big file to count the number of words repeat K times读一个大文件统计单词重复K次的次数
【发布时间】:2017-06-20 06:15:31
【问题描述】:

问题

有一个巨大的文件(10GB),必须读取文件并打印出文件中精确重复k次的单词数

我的解决方案

  1. 使用ifstream逐字读取文件;
  2. 将单词插入地图std::map<std::string, long> mp; mp[word] += 1;
  3. 读取文件后,查找地图中的所有单词以获取出现k次的单词

问题

  1. 如何使用多线程有效读取文件[按块读取]?要么 任何提高读取速度的方法。
  2. 有没有比map更好的数据结构可以有效的找到输出?

文件信息

  1. 每行最多 500 字
  2. 每个单词的最大长度为 100 个字符

【问题讨论】:

    标签: c++ data-structures c++14 fstream


    【解决方案1】:

    如何使用多线程有效地读取文件[按块读取]?或任何提高读取速度的方法。

    我一直在尝试实际结果,与我之前的建议不同,多线程是一件好事。无线程版本运行时间为 1m44,711s,4 线程版本(4 核)运行时间为 0m31,559s,8 线程版本(4 核 + HT)运行时间为 0m23,435s。然后是重大改进 - 加速几乎是 5 倍。

    那么,您如何分配工作量?将其拆分为 N 个块(n == 线程数),并让每个线程首先查找第一个非单词字符,但第一次查找除外。这是他们逻辑块的开始。它们的逻辑块在它们的结束边界处结束,四舍五入到该点之后的第一个非单词字符。

    并行处理这些块,将它们全部同步到一个线程,然后让该线程合并结果。

    接下来要提高阅读速度,最好的办法是确保尽可能不复制数据。通读内存映射文件并通过保持指向开始和结束的指针或索引来查找字符串,而不是累积字节。

    有没有比map更好的数据结构可以有效的找到输出?

    好吧,因为我认为您不会使用订单,所以 unordered_map 是一个更好的选择。我也会把它设为unordered_map<std::string_view, size_t> - string_view 复制它的次数甚至比 string 少。

    在分析时,我发现 53% 的时间都花在找到包含给定单词的确切存储桶上。

    【讨论】:

    • 不是std::string_view c++17?
    • std::string_view 是 c++17。你也可以使用 boost::string_view,或者无论如何都要点击并复制。
    【解决方案2】:

    如果您有 64 位系统,那么您可以对文件进行内存映射,并使用例如this solution to read from memory.

    结合the answer from dascandy std::unordered_mapstd::string_view(如果有的话),你应该尽可能快地进入一个线程。您可以使用std::unordered_multiset 代替std::unordered_map,我不知道哪个“更快”。

    使用线程很简单,只要做你知道的事情,但每个线程只处理文件的一部分。在所有线程完成后合并地图。 但是当您将文件拆分为每个线程的块时,您就有可能在中间拆分单词。处理这件事并非易事。

    【讨论】:

    • .. 对。有些系统没有 10 GB 的地址空间。 unordered_multiset 不会更快,因为它必须跟踪更多数据。如果您确实想做多线程,请将其拆分为 N 个块(n == 线程数)并让每个线程,但首先查找第一个非单词字符。然后让所有句柄词,包括从结尾开始的词(最后一个块除外)。然后当它们全部完成时,合并并同步它们。请注意,处理 10GB 将需要 1 秒的大小(假设已加载),并且线程会增加大约 2 秒的开销。
    猜你喜欢
    • 2017-10-22
    • 2022-12-12
    • 1970-01-01
    • 2023-04-04
    • 2021-04-13
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多