【问题标题】:Is there a way to seek the "\n" character that is faster than looping through char one at a time?有没有一种方法可以找到比一次循环一个字符更快的 \"\\n\" 字符?
【发布时间】:2022-11-15 18:55:38
【问题描述】:

在计算行数时查看 sample implementation of wc.c,它循环遍历文件,一次一个字符并累积 '\n' 以计算换行数:

#define COUNT(c)       \
      ccount++;        \
      if ((c) == '\n') \
        lcount++;
  • 有没有一种方法可以只查找 '\n' 的文件并继续跳转到换行符并进行计数?

  • 寻找 '\n' 是否与一次读取一个字符相同,直到我们看到 '\n' 并计算它?

【问题讨论】:

  • 你已经问过这个了,答案是否定的,否则 wc 会这样做
  • 如果不寻找它们,“寻求”如何知道 '\n' 在哪里?
  • 是什么让您认为 \n 很特别?如果任务是计算字母 a 的出现次数,您会问同样的问题吗?
  • 不幸的是,文件没有表示为某种多维结构,\n 只是另一个字符。所有计算数组中元素出现次数的算法(我知道)都具有线性复杂度。例如。 en.cppreference.com/w/cpp/algorithm/count
  • 最后,它始终是内存使用和速度之间的权衡。假设您使用的是带有 avx512 的 CPU。您可以将整个文件映射到内存中,然后将其分成与内核数一样多的内存段。确保各分区以 512 位对齐。然后为每个核心启动一个线程(并赋予它与特定核心的线程关联性,以最佳地利用缓存,(MIMD)。然后在每个线程上矢量化搜索'\n',以便可以使用 avx512 检查 64bytes并行(SIMD)。然后你可能仍然需要分析来优化。

标签: c++ string count newline wc


【解决方案1】:

好吧,不是所有字符都不是' ',除了一个。 无分支算法可能更快。
你试过std::count了吗?

#include <string>
#include <algorithm>

int main() {
  const auto s = std::string("Hello, World!
foo
bar
baz");
  const auto lines_in_s = std::count(s.cbegin(), s.cend(), '
');
  return lines_in_s;
}

Compiler Explorer

或者使用文件:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <string>

int main() {
    if (std::ifstream is("filename.txt"); is) {
        const auto lines_in_file =
            std::count(std::istreambuf_iterator<char>(is),
                       std::istreambuf_iterator<char>{}, '
');

        std::cout << lines_in_file << '
';
    }
}

Compiler Explorer

【讨论】:

  • 我同意惯用的解决方案(除了使用内存映射文件和使用执行策略可以更快地完成它) - 但你所说的“无分支”是什么意思? std::count 不是无分支 afaik。
【解决方案2】:

你可以跳过看每个角色的唯一方法是如果你有领域知识关于您当前正在查看的字符串:

如果你知道如果您正在处理包含至少 50 个单词左右的连续段落的文本,您可以在每个 ' ' 之后前进 100 或 200 个字符,从而节省一些时间。当然,您需要测试和改进该跳跃长度,但是您不需要检查每个字符。

对于通用计数功能,您必须查看每个可能的字符。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 2021-01-21
    相关资源
    最近更新 更多