【问题标题】:C++ : Fastest way to read string from stdinC++:从标准输入读取字符串的最快方法
【发布时间】:2014-03-20 08:31:15
【问题描述】:

我们可以使用 getchar_unlocked 来从标准输入快速读取整数,方法是操作如下字符:

int scan_d()
{
    int ip = getchar_unlocked(), ret = 0, flag = 1;

    for(; ip < '0' || ip > '9'; ip = getchar_unlocked())
    {
        if(ip == '-')
        {
            flag = -1;
            ip = getchar_unlocked();
            break;
        }
    }

    for(; ip >= '0'&& ip <= '9'; ip = getchar_unlocked())
        ret = ret * 10 + ip - '0';
    return flag * ret;
}

有没有办法使用上面的方法快速从标准输入读取字符串? get 比 cin/scanf 快,但同时拥有对空格的关键处理。我想修改上面的字符串代码,但遇到了空格问题。此外,似乎一个一个地读取字符串的每个字符会更慢。

标准输入是指用户输入的字符串(无文件处理)

【问题讨论】:

  • 这有过早优化的味道。
  • getchar_unlocked 看起来也是一个非标准函数。
  • c++ 中没有类似 getchar_unlocked() 的方法,你在说什么?
  • @πάνταῥεῖ 因为他指的是getchar_unlocked(),我猜这意味着它是getchar 的版本,没有同步。 std::cin 必须跨线程同步,并且默认与 cstdio 同步。当您添加每个字符的虚拟调用开销时,使用std::cin 的哪种方法并不重要,它们都会比getchar_unlocked 慢。 OTOH,这纯粹是过早的优化。
  • "有没有办法使用类似上面的方法快速从标准输入读取字符串?" 并且由于 "我的意思是标准输入是由用户(无文件处理)”,答案很明确:以更快的用户。 ;)

标签: c++ input getchar


【解决方案1】:

有没有办法使用上面的方法快速从标准输入读取字符串?

当然。如果您更清楚您期望它的行为方式,我们甚至可以提供代码。

gets 比 cin/scanf 更快,但同时拥有对空格的关键处理。

cin 和 scanf 也可以做到这一点:How to cin Space in c++? 和 How do you allow spaces to be entered using scanf?

我想修改上面的字符串代码,但遇到了空格问题。

什么问题? https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem

此外,似乎逐个读取字符串的每个字符会更慢。

比块读取慢?当然。但是,一次读取一个字符实际上是判断字符串末尾在哪里的唯一方法。您可以阻止读取到缓冲区并旋转以找到字符串的结尾,这称为缓冲。但是stdin 已经被缓冲了,所以再次缓冲它会使它变慢而不是变快。没有比使用getchar_unlocked 一次一个字符更快地读取空格分隔字符串的方法了。

【讨论】:

    【解决方案2】:

    不确定我的基准测试是否正确。这真的是我第一次测试速度。

    不管怎样,这里是:

    http://ideone.com/KruGD2

    #include <cstdio>
    #include<iostream>
    #include <sstream>
    #include <chrono>
    
    std::chrono::time_point<std::chrono::steady_clock> hClock()
    {
        return std::chrono::steady_clock::now();
    }
    
    std::uint32_t TimeDuration(std::chrono::time_point<std::chrono::steady_clock> Time)
    {
        return std::chrono::duration_cast<std::chrono::nanoseconds>(hClock() - Time).count();
    }
    
    
    void Benchmark(const char* Name, std::string &str, void(*func)(std::string &str))
    {
        auto time = hClock();
        for (int i = 0; i < 100; ++i)
        {
            func(str);
            str.clear();
        }
        std::cout<<Name<<" took: "<<TimeDuration(time) / 100<<" nano-seconds.\n";
    }
    
    void unlocked_bench(std::string &str)
    {
        char c = '0';
        while((c = getchar_unlocked()) && (c != -1 && c != '\n' && c != '\r'))
        {
            str += c;
        }
    }
    
    void getchar_bench(std::string &str)
    {
        char c = '0';
        while((c = getchar())  && (c != -1 && c != '\n' && c != '\r'))
        {
            str += c;
        }
    }
    
    void getline_bench(std::string &str)
    {
        std::cin.getline(&str[0], str.size());
    }
    
    void scanf_bench(std::string &str)
    {
        scanf("%[^\n]100s", &str[0]);
    }
    
    void fgets_bench(std::string &str)
    {
        fgets(&str[0], str.size(), stdin);
    }
    
    void cinread_bench(std::string &str)
    {
        std::cin.read(&str[0], str.size());
    }
    
    int main()
    {
        std::string str;
        str.reserve(100);
    
        Benchmark("getchar_unlocked", str, unlocked_bench);
        Benchmark("getchar", str, getchar_bench);
        Benchmark("getline", str, getline_bench);
        Benchmark("scanf", str, scanf_bench);
        Benchmark("fgets", str, fgets_bench);
        Benchmark("cinread", str, cinread_bench);
    
        return 0;
    }
    

    输入:

    Hello There
    Hello There
    Hello There
    Hello There
    Hello There
    Hello There
    

    输出:

    getchar_unlocked took: 436 nano-seconds.
    getchar took: 330 nano-seconds.
    getline took: 619 nano-seconds.
    scanf took: 522 nano-seconds.
    fgets took: 44 nano-seconds.
    cinread took: 67 nano-seconds.
    

    【讨论】:

    • 我阅读了 fgets 上的文档,你在那里做得很好。另外,我认为 ideone 在单独的服务器上运行这些以获取准确的时间(它是 SPOJ 的一部分)因此,我尝试修复您的测试,但我遇到了获取问题。 ideone.com/IbfD2E 它确实清楚地表明getchar_unlocked 是最快的,而 istreams 最慢到目前为止。
    • 好的,现在怎么样..我改变了基准..现在可以了吗?
    • 添加了cin.read。 @MooingDuck 我使用了 ideone,因为我没有 linux 系统来访问 getchar_unlocked atm。它不能在 Windows 上的 Mingw 4.8.1 中编译。在 MSVC 2013 中也不起作用。 Ideone 是我唯一的选择。
    • @ThomasMatthews:cin.read 没有表现出与其他人相同的行为。执行的函数是 cin.getline,它已经在我的测试中
    • @CantChooseUsernames:实际上,您在这个答案上做得很好,除了您正在阅读 500 行但只提供 12 行。
    【解决方案3】:

    由于人类比计算机慢,因此没有快速的方法可以将用户的输入输入到您的程序中。

    如果用户以每分钟 1 个字母的速度输入,您的程序将等待 1 分钟等待下一个字符。时期。不能更快地阅读。

    如果您的程序每秒可以从用户那里读取 1 个字符,而我的程序需要 1 毫秒来读取一个字符,那么这两个程序最终都会等待 60,000 毫秒来等待下一个用户的字符。我的程序更快吗?是的。这有什么不同吗?不。你开到红灯的速度比我快吗?

    根据我的经验,有关用户输入的所有优化都已关闭。不要打扰。 It wastes your time and annoys the pig.

    如果你的程序需要 30 秒来执行一个操作,它仍然需要再等待 30 秒让用户输入下一个字符。

    专注于稳健性:

    • 用户可以输入无效值吗?
    • 您的程序如何告诉用户该值无效?
    • 用户输入的字符数能否超过缓冲区支持的字符数?

    如果必须,阻止从用户读取或使用getline 读取字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-19
      • 2021-11-18
      • 2023-03-11
      相关资源
      最近更新 更多