7

我注意到,如果我使用 cout 打印出一个长字符串(char*),它似乎在 Windows 7、Vista 和 Linux(使用 putty)中使用 Windows 上的 Visual C++ 2008 和 Linux 上的 G++ 一次打印 1 个字符。Printf 快得多,我实际上在我的一个项目中从 cout 切换到 printf 进行大多数打印。这让我很困惑,因为这个问题让我觉得我是唯一一个遇到这个问题的人。

我什至写了一个 cout 替代品,看起来它在我的 comp 上击败了 cout 的裤子 -

class rcout
{
public:
    char buff[4096];
    unsigned int size;
    unsigned int length;

    rcout()
    {
        size = 4096;
        length = 0;
        buff[0] = '\0';
    }

    ~rcout()
    {
        printf("%s", buff);
    }

    rcout &operator<<(char *b)
    {
        strncpy(buff+length, b, size-length);
        unsigned int i = strlen(b);
        if(i+length >= size)
        {
            buff[size-1] = '\0';
            printf("%s", buff);
            b += (size-length) -1;
            length = 0;
            return (*this) << b;
        }
        else
            length += i;
        return (*this);
    }

    rcout &operator<<(int i)
    {
        char b[32];
        _itoa_s(i, b, 10);
        return (*this)<<b;
    }

    rcout &operator<<(float f)
    {
        char b[32];
        sprintf_s(b, 32, "%f", f);
        return (*this)<<b;
    }
};

int main()
{
    char buff[65536];
    memset(buff, 0, 65536);

    for(int i=0;i<3000;i++)
        buff[i] = rand()%26 + 'A';

    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);
    cout << "\n\nOk, now cout....\n\n";
    cout << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);
    cout << "\n\nOk, now me again....\n\n";
    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);

    return 0;
}

任何想法为什么 cout 对我来说打印速度如此缓慢?

4

8 回答 8

12

注意:此实验结果对 MSVC 有效。在库的其他一些实现中,结果会有所不同。

printf 可能(比)快得多cout。尽管printf在运行时解析格式字符串,但与cout. 以下是我的实验总结:

静态指令数

一般来说,cout生成的代码比printf. 假设我们有以下cout代码可以使用某些格式打印出来。

os << setw(width) << dec << "0x" << hex << addr << ": " << rtnname <<
  ": " << srccode << "(" << dec << lineno << ")" << endl;

在经过优化的 VC++ 编译器上,它会生成大约188字节的代码。但是,当您替换printf基于 it 的代码时,只需要42个字节。

动态执行的指令数

静态指令的数量只是说明静态二进制代码的区别。更重要的是在运行时动态执行的实际指令数。我还做了一个简单的实验:

测试代码:

int a = 1999;
char b = 'a';
unsigned int c = 4200000000;
long long int d = 987654321098765;
long long unsigned int e = 1234567890123456789;
float f = 3123.4578f;
double g = 3.141592654;

void Test1()
{
    cout 
        << "a:" << a << “\n”
        << "a:" << setfill('0') << setw(8) << a << “\n”
        << "b:" << b << “\n”
        << "c:" << c << “\n”
        << "d:" << d << “\n”
        << "e:" << e << “\n”
        << "f:" << setprecision(6) << f << “\n”
        << "g:" << setprecision(10) << g << endl;
}

void Test2()
{
    fprintf(stdout,
        "a:%d\n"
        "a:%08d\n"
        "b:%c\n"
        "c:%u\n"
        "d:%I64d\n"
        "e:%I64u\n"
        "f:%.2f\n"
        "g:%.9lf\n",
        a, a, b, c, d, e, f, g);
    fflush(stdout);
}

int main()
{
    DWORD A, B;
    DWORD start = GetTickCount();
    for (int i = 0; i < 10000; ++i)
        Test1();
    A = GetTickCount() - start;

    start = GetTickCount();
    for (int i = 0; i < 10000; ++i)
        Test2();
    B = GetTickCount() - start;
    
    cerr << A << endl;
    cerr << B << endl;
    return 0;
}

这是 Test1 (cout) 的结果:

  • # 执行指令:423,234,439
  • # 内存加载/存储:大约。320,000 和 980,000
  • 经过时间:52秒

那么,呢printf?这是Test2的结果:

  • # 执行指令:164,800,800
  • # 内存加载/存储:大约。70,000 和 180,000
  • 经过时间:13秒

在这台机器和编译器printf中,速度要快得多cout。在执行指令的数量和加载/存储的数量(表示缓存未命中的数量)中都有 3~4 倍的差异。

我知道这是一个极端的例子。另外,我应该指出,cout当您处理 32/64 位数据并需要 32/64 平台独立性时,这要容易得多。总是有取舍。cout当检查类型非常棘手时,我正在使用。

好吧,cout在 MSVS 中简直糟透了 :)

于 2009-11-15T01:53:39.413 回答
9

我建议您在另一台计算机上尝试相同的测试。对于为什么会发生这种情况,我没有很好的答案。我只能说我从未注意到 cout 和 printf 之间的速度差异。我还在 Linux 上使用 gcc 4.3.2 测试了您的代码,但没有任何区别。

话虽如此,您不能轻易地将 cout 替换为您自己的实现。事实上,cout 是 std::ostream 的一个实例,它内置了很多功能,这对于与其他重载 iostream 运算符的类的互操作性是必需的。

编辑:

任何说printf总是比std::cout简单错误的人更快的人。 我刚刚运行了 minjang 发布的测试代码,在 64 位 AMD Athlon X2 上使用 gcc 4.3.2 和 -O2 标志,并且 cout 实际上更快

我得到以下结果:

printf: 00:00:12.024
cout:   00:00:04.144

cout 总是比 printf 快吗?可能不是。特别是对于较旧的实现。但是在较新的实现中,iostream 可能比 stdio 更快,因为编译器不是在运行时解析格式字符串,而是在编译时知道它需要调用哪些函数才能将整数/浮点数/对象转换为字符串。

但更重要的是, printf 与 cout 的速度取决于 implementation,因此 OP 描述的问题不容易解释。

于 2009-11-15T01:42:53.803 回答
4

在使用 std::cout/cin 之前尝试调用ios::sync_with_stdio(false);,当然,除非您在程序中混合 stdio 和 iostream,这是一件坏事。

于 2009-11-15T02:05:04.693 回答
1

根据我在编程比赛中的经验,printf 比 cout 快。

cin我记得很多次我的解决方案因为/没有在时间限制之前完成cout,而printf/scanf确实有效。

cout除此之外,看起来比 慢的(至少对我来说)是正常的printf,因为它做了更多的操作。

于 2009-11-15T01:52:52.190 回答
0

尝试使用一些endls 或flushes ,因为它们会刷新cout的缓冲区,以防操作系统出于任何原因缓存您的程序的输出。但是,正如查尔斯所说,这种行为没有很好的解释,所以如果这没有帮助,那么它可能是您的机器特有的问题。

于 2009-11-15T01:44:47.477 回答
0

您应该尝试将所有数据写入ostringstream第一个,然后coutostringstream's上使用str()。我在 64 位 Windows 7 上并且Test1已经明显快于Test2(您的里程可能会有所不同)。首先使用 anostringstream构建单个字符串,然后使用couton进一步减少 Test13 到 4 倍的执行时间。一定要#include <sstream>.

即,更换

void Test1()
{
    cout
        << "a:" << a << "\n"
        << "a:" << setfill('0') << setw(8) << a << "\n"
        << "b:" << b << "\n"
        << "c:" << c << "\n"
        << "d:" << d << "\n"
        << "e:" << e << "\n"
        << "f:" << setprecision(6) << f << "\n"
        << "g:" << setprecision(10) << g << endl;
}

和:

void Test1()
{
    ostringstream oss;
    oss
        << "a:" << a << "\n"
        << "a:" << setfill('0') << setw(8) << a << "\n"
        << "b:" << b << "\n"
        << "c:" << c << "\n"
        << "d:" << d << "\n"
        << "e:" << e << "\n"
        << "f:" << setprecision(6) << f << "\n"
        << "g:" << setprecision(10) << g << endl;
    cout << oss.str();
}

我怀疑ostringstream由于每次调用时都没有尝试写入屏幕,这会变得如此之operator<<cout。我还通过经验注意到,减少你在屏幕上写的次数(通过一次写更多)可以提高性能(同样,你的里程可能会有所不同)。

例如,

void Foo1()
{
    for(int i = 0; i < 10000; ++i) {
        cout << "Foo1\n";
    }
}

void Foo2()
{
    std::string s;
    for(int i = 0; i < 10000; ++i) {
        s += "Foo2\n";
    }
    cout << s;
}

void Foo3()
{
    std::ostringstream oss;
    for(int i = 0; i < 10000; ++i) {
        oss << "Foo3\n";
    }
    cout << oss.str();
}

就我而言,Foo1花了 1,092 毫秒、Foo2234 毫秒和Foo3218 毫秒。 ostingstreams是你的朋友。显然 Foo2 和 Foo3 需要(微不足道的)更多内存。要将其与 C 样式函数进行比较,请尝试sprintf进入缓冲区,然后使用写入该缓冲区fprintf,您应该会看到效率更高Test2(尽管对我而言,这仅提高Test2了大约 10% 左右的性能;cout并且printf确实是不同的野兽引擎盖)。

编译器:MinGW64(TDM 及其捆绑的库)。

于 2014-02-04T17:17:45.210 回答
0

尝试使用ios::sync_with_stdio(false);. 在使用 std::cin/cout 之前提及它。它不混合 stdio 或 iostream,但它将 iostream 标准流与其相应的标准 c 流同步。例如 - iostream 的 std::cin/wcin 与 c 流的 stdin 同步

于 2015-04-18T08:53:53.987 回答
-2

这是应该使 c++ 流与 c printf 一样快的 hax。我从未测试过它,但我相信它有效。

ios_base::sync_with_stdio(0);
于 2009-11-15T02:04:37.487 回答