阅读一个大文件来计算重复K次的单词数

Read a big file to count the number of words repeat K times

本文关键字:计算 单词数 文件 一个      更新时间:2023-10-16

问题

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

我的解决方案

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

问题

  1. 如何使用多线程有效地读取文件[按块读取]?或 任何提高读取速度的方法。
  2. 除了map之外,是否有更好的数据结构可以有效地找到输出?

文件信息

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

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

我一直在尝试实际结果,与我之前的建议不同,多线程是一件好事。非线程变体以 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复制它甚至比字符串更少。

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

如果你有一个64位系统,那么你可以对文件进行内存映射,并使用例如这个解决方案从内存中读取。

结合 dascandy 关于std::unordered_mapstd::string_view的答案(如果有的话),您应该尽可能快地在单个线程中获得。你可以用std::unordered_multiset而不是std::unordered_map,我不知道哪一个"更快"。

使用线程很简单,只需执行您所知道的操作,但每个线程仅处理文件的一部分。在所有线程完成后合并映射。但是,当您为每个线程将文件拆分为块时,您可能会在中间拆分单词。处理这个问题并非易事。