【问题标题】:Which is the fastest method of input in C++ [closed]哪种是 C++ 中最快的输入方法 [关闭]
【发布时间】:2012-04-02 14:17:25
【问题描述】:

我正在为各种编程奥林匹克编码,并试图提高时间效率。我正在寻找获取输入的最快方法,使用 gcc 编译器,无需任何外部库。

我之前使用过 cin 和 cout,但发现 scanf 和 printf 的速度要快得多。有没有更快的方法?我不太关心空间复杂性,我更喜欢更好的时间。

【问题讨论】:

  • 您是在寻找实施时间还是运行时间?对于运行时,您可能会对我的回答感兴趣:stackoverflow.com/a/8854366/365496
  • 文件在比赛中不是很常见吗?光纤通道 SAN 驱动器让它们真的快:)

标签: c++ performance time


【解决方案1】:

流总是比 C-API 函数慢是一个很常见的误解,因为默认情况下,它们与 C 层同步。所以是的,这是一个特性,而不是一个错误。

在不牺牲类型安全(和可读性,取决于您的喜好)的情况下,您可以通过以下方式获得流的性能:

std::ios_base::sync_with_stdio (false);

一个小指标:

#include <cstdio>
#include <iostream>

template <typename Test> 
void test (Test t)
{
    const clock_t begin = clock();
    t();
    const clock_t end = clock();
    std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}

void std_io() {
    std::string line;
    unsigned dependency_var = 0;
    
    while (!feof (stdin)) {
        int c;
        line.clear();
        while (EOF != (c = fgetc(stdin)) && c!='\n')
            line.push_back (c);
        dependency_var += line.size();
    }
    
    std::cout << dependency_var << '\n';
}

void synced() {
    std::ios_base::sync_with_stdio (true);
    std::string line;
    unsigned dependency_var = 0;
    while (getline (std::cin, line)) {
        dependency_var += line.size();
    }
    std::cout << dependency_var << '\n';
}

void unsynced() {
    std::ios_base::sync_with_stdio (false);
    std::string line;
    unsigned dependency_var = 0;
    while (getline (std::cin, line)) {
        dependency_var += line.size();
    }
    std::cout << dependency_var << '\n';
}

void usage() { std::cout << "one of (synced|unsynced|stdio), pls\n"; }

int main (int argc, char *argv[]) {
    if (argc < 2) { usage(); return 1; }
    
    if (std::string(argv[1]) == "synced") test (synced);
    else if (std::string(argv[1]) == "unsynced") test (unsynced);
    else if (std::string(argv[1]) == "stdio") test (std_io);
    else { usage(); return 1; }

    return 0;
}

使用 g++ -O3 和一个大文本文件:

cat testfile | ./a.out stdio
...
0.34 sec

cat testfile | ./a.out synced
...
1.31 sec

cat testfile | ./a.out unsynced
...
0.08 sec

这取决于您的情况。修改这个玩具基准,添加更多测试,并比较例如类似于std::cin &gt;&gt; a &gt;&gt; b &gt;&gt; cscanf ("%d %d %d", &amp;a, &amp;b, &amp;c);。我保证,通过优化(即不处于调试模式),性能差异将是微妙的。

如果这不能满足您的需求,您可以尝试其他方法,例如首先读取整个文件(可能会或可能不会带来更多性能)或内存映射(这是一种非便携式解决方案,但大型桌面有它们)。


更新

格式化输入:scanf 与流

#include <cstdio>
#include <iostream>

template <typename Test> 
void test (Test t)
{
    const clock_t begin = clock();
    t();
    const clock_t end = clock();
    std::cout << (end-begin)/double(CLOCKS_PER_SEC) << " sec\n";
}

void scanf_() {
    char x,y,c;
    unsigned dependency_var = 0;
    
    while (!feof (stdin)) {
        scanf ("%c%c%c", &x, &y, &c);
        dependency_var += x + y + c;
    }
    
    std::cout << dependency_var << '\n';
}

void unsynced() {
    std::ios_base::sync_with_stdio (false);
    char x,y,c;
    unsigned dependency_var = 0;
    while (std::cin) {
        std::cin >> x >> y >> c;
        dependency_var += x + y + c; 
    }
    std::cout << dependency_var << '\n';
}

void usage() { std::cout << "one of (scanf|unsynced), pls\n"; }

int main (int argc, char *argv[]) {
    if (argc < 2) { usage(); return 1; }
    
    if (std::string(argv[1]) == "scanf") test (scanf_);
    else if (std::string(argv[1]) == "unsynced") test (unsynced);
    else { usage(); return 1; }

    return 0;
}

结果:

scanf: 0.63 sec
unsynced stream: 0.41 

【讨论】:

  • 流比 C-API 慢,但这是有原因的(它做了很多工作)。它在读取器/写入器中内置了整个 Locale 内容,而 C-API 中不存在,这可能很昂贵(尽管尝试使用“C”语言环境将其最小化(但它仍然存在))。这里我们假设我们使用格式化的输入/输出而不是直接读/写。
  • @LokiAstari:不一定。 scanf 总是需要解析格式字符串,而对于流,它在运行时不存在。
  • @LokiAstari:提供的格式化输入示例。在第一次阅读时忽略它(对不起):C-io 也使用语言环境(linux.die.net/man/3/setlocale)。
  • @SebastianMach 先生,我需要和你谈谈,我们可以聊聊吗?
【解决方案2】:

一般来说,缓冲输入是最快的。刷新输入缓冲区的频率越低,输入速度就越快。有关完整且内容丰富的讨论,请参阅this question。简而言之,具有大缓冲区大小的 read() 会尽可能快,因为它几乎直接位于操作系统中相应的系统调用之上。

【讨论】:

    【解决方案3】:

    可能 scanf 比使用流要快一些。尽管流提供了很多类型安全性,并且不必在运行时解析格式字符串,但它通常具有不需要过多内存分配的优点(这取决于您的编译器和运行时)。也就是说,除非性能是您唯一的最终目标并且您处于关键路径中,否则您应该真正偏爱更安全(更慢)的方法。

    Herb Sutter 在这里写了一篇非常好吃的文章

    http://www.gotw.ca/publications/mill19.htm

    谁详细介绍了 sscanf 和 lexical_cast 等字符串格式化程序的性能,以及是什么因素导致它们运行缓慢或快速。这有点类似,可能类似于会影响 C 风格 IO 和 C++ 风格之间性能的那种事情。与格式化程序的主要区别往往是类型安全和内存分配的数量。

    【讨论】:

    • 请注意,默认情况下流与 C-API 同步。如果您禁用同步,流通常会与 C-API 一样快,有时甚至比 C-API 更快。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-25
    • 2011-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多