【问题标题】:Cause for this difference..from C++ to C?造成这种差异的原因..从 C++ 到 C?
【发布时间】:2011-07-08 00:44:10
【问题描述】:

我想知道为什么会一直发生这种情况...!! 我编写了两个程序,一个用 c 编写,另一个用 c++ 编写。两者执行相同的操作。即打印从 1 到 2000000 的数字。另外,我在执行开始时设置计时器.. 打印完所有数字后,还打印了经过的时间.. c++ 程序所用的时间总是比 c 程序长。 我觉得时间差异很大。我很想知道这是什么原因..????..

这是两个程序

//iotest.c

#include<stdio.h>
#include<time.h>

clock_t start=clock();

int main()
{
for(int i=0;i<2000000;i++)

printf("%d\n",i);

printf("Time Elapsed: %f\n",((double)clock()-start)/CLOCKS_PER_SEC);

return 0;

}

//iotest.cpp

#include<iostream>

#include<time.h>

using namespace std;

clock_t start=clock();

int main()
{
    for(int i=0;i<2000000;i++)

    cout<<i<<endl;

    cout<<"Time elapsed "<<((double)clock()-start)/CLOCKS_PER_SEC<<endl;

    return 0;

}

// 版本 C++ 4.3.2 通过发出命令编译c程序

g++ iotest.c

执行给予

1

.

.

2000000

经过的时间:5.410000(并不总是相同..)

执行第二个程序

1

.

.

2000000

经过的时间:5.81(并不总是相同..)

【问题讨论】:

  • 你的编译命令是什么,实际运行时间是多少?
  • 每个用了多少时间?您使用的是哪个 C 编译器?您使用的是哪个 C++ 编译器?您在哪个操作系统中执行这些操作?
  • 尝试将&lt;&lt; endl 替换为&lt;&lt; '\n'。 endl 也会刷新流。别忘了告诉我们结果:)
  • 这些都是 C++ 程序。您在比较 stdio 和 iostream,而不是 C 和 C++。
  • 你真的可以在 C 中的函数之外 clock_t start=clock(); 吗?这是 C1x 中的新事物之一,还是 gcc 扩展?

标签: c++ c


【解决方案1】:

这两个程序的区别在于 C++ 版本使用endl,它不仅插入换行符,而且刷新缓冲区。执行任何输出的缓慢部分是刷新缓冲区。

如果你使用 C++ 程序,这两个程序的速度可能差不多

count << i << "\n";

以下两个程序实现了相似的执行时间:

C 程序 (a.c):

#include <stdio.h>
#include <time.h>

int main()
{
    clock_t start=clock();
    for (int i=0; i<2000000; i++) printf("%d\n",i);
    clock_t end=clock();

    fprintf(stderr, "Time Elapsed: %f\n",((double)end-start)/CLOCKS_PER_SEC);
    return 0;
}

编译:gcc -O3 -std=c99 a.c

C++ 程序 (b.cpp):

#include <iostream>
#include <ctime>

using namespace std;

int main()
{
    clock_t start=clock();
    for (int i=0;i<2000000;i++) cout << i << '\n';
    clock_t end=clock();

    cerr << "Time elapsed " << ((double)end-start)/CLOCKS_PER_SEC << endl;

    return 0;
}

使用g++ -O3 b.cpp编译

【讨论】:

  • 但是如果输出设备可以被确定为终端,C 无论如何都会使用行缓冲,所以假设输出没有被重定向,那么它还有更多的功能。
  • @paxdiablo:你看到 Magnus 的编辑了吗?将endl 更改为'\n' 会使程序执行相同的操作。
  • 是的,但根据我对标准的了解,我认为它其他不仅仅是冲洗。我可能是错的,这不是第一次,但经验证据就是——经验的。我不相信太阳每天早上都会升起,只是因为它总是如此,而是因为我了解它背后的科学。
  • 在胡思乱想之后,我发现强制刷新两个程序中的每一行,然后重定向到/dev/null 运行使a.c 领先约12%。避免在两个程序中刷新并重定向到/dev/null 使运行时相同(或者如果存在差异,它对 b.cpp 有利。我不是统计学家)。这证实了@paxdiablo 的分析。
  • 我已经多次看到这个endl 感到惊讶,以至于我不禁怀疑将EOL 和flush 打包在同一个对象中是否不是设计错误。没有初学者能理解它,专家们很难学会它。
【解决方案2】:

您已在静态初始化时开始计时,而您的 C++ 标准库在静态初始化期间可能还有更多工作要做。

你也在反复刷新你的流,而且 iostream 有点慢。

这样做:

#include <iostream>
#include <ctime>

int main()
{
    std::clock_t start = std::clock();
    for (int i=0;i<2000000;i++)
       std::cout << i << '\n';
    std::cout << "Time elapsed " << (static_cast<double>(std::clock()-start)/CLOCKS_PER_SEC) << std::endl;
    return 0;
}

适当的基准测试需要您多次运行该程序,然后取结果的平均值。你得到的结果根本不可靠。

(还要注意我是如何将 time.h 更改为 C++ 对应的 ctime。)

【讨论】:

  • 非常敏锐。在静态初始化时开始计时确实是 C 和 C++ 之间的主要区别,差异如此之大,我认为这是一个严重的错误。我怀疑这对效率的影响远大于缓冲区刷新问题。
  • @Xplore:您是否选择性地忽略了我指出的其他问题?
  • 如果我错了请纠正我,但我相信它必须是std::clock_t start = std::clock();(&lt;ctime&gt; 将&lt;time.h&gt; 的内容放入命名空间std)。
  • @Billy:实际上,你是对的。我太习惯于对 GCC 随意放肆了,抱歉。 :)
  • @tomalak。起初我忽略了认为它不会有太大区别..编辑后,两个程序都给出了相似(或多或少)的结果..感谢您的通知...
【解决方案3】:

使用cout &lt;&lt; endl 将强制刷新。如果您使用cout &lt;&lt; "\n"

,则差异可能会更低

也就是说,iostreams(在我个人看来)不是最有效的机制,我希望 printf 仍然更快。如果输出速度是应用程序的性能瓶颈,您可能应该 fwrite 到 stdout,否则只需坚持类型安全 cout。

【讨论】:

  • 您的第二段可能是正确的,但如果 C 是终端,则 C 在 stdout 上使用行缓冲。所以我怀疑冲洗不是问题,除非你重定向标准输出。
【解决方案4】:

这是因为std::cout 的设计与printf() 不同。你在性能上损失了什么,你在可维护性上得到了回报(例如类型安全、使用灵活性、结构化语法等)。 iostream 库是 C++ 标准库中最庞大的部分之一,因此这并不奇怪。

看看汇编输出,你会亲眼看到。

【讨论】:

    【解决方案5】:

    C++ 有点高级,流的工作方式似乎与 printf 非常不同,C 和 C++ 编译器都会生成不同的代码。

    【讨论】:

      【解决方案6】:

      我认为瓶颈在于数据的格式。我更改了 Gabe 的示例,将一个常量字符数组输出到控制台(以尽量减少因整数格式化而产生的影响):

      交流

      include <stdio.h>
      #include <time.h>
      
      int main()
      {
          static const char   hello[] = "hello\n";
          clock_t start=clock();
          for (int i=0; i<2000000; i++) printf("%s",hello);
          clock_t end=clock();
      
          fprintf(stderr, "Time Elapsed: %f\n",((double)end-start)/CLOCKS_PER_SEC);
          return 0;
      }
      

      b.cpp:

      #include <iostream>
      #include <ctime>
      
      using namespace std;
      
      int main()
      {
          static const char   hello[] = "hello\n";
          clock_t start=clock();
          for (int i=0;i<2000000;i++) cout << hello;
          clock_t end=clock();
      
          cerr << "Time elapsed " << ((double)end-start)/CLOCKS_PER_SEC << endl;
      
          return 0;
      }
      

      编译语句:

      gcc -mno-cygwin -O3 -std=c99 a.c
      g++ -mno-cygwin -O3 -o b.exe b.cpp
      

      可执行尺寸:

      # ls -al *.exe
      -rwxr-xr-x 1 Thomas root  49052 Mar  3 12:00 a.exe
      -rwxr-xr-x 1 Thomas root 503195 Mar  3 12:01 b.exe
      

      性能(在独立 XP 上运行,具有最少的操作系统和应用程序):

      a.c:  Time elapsed: 187.359
      b.cpp: Time elapsed: 120.718
      

      C++ 程序可能运行得更快,因为它正在调用针对数据量身定制的方法。 printf 仍然需要在打印之前扫描格式字符串。

      在得出任何实质性结论之前,应该对“fwrite”与“cout.write()”进行对比以获得基线。这将是从其他比较中减去的时间,因为它代表系统的 I/O 开销。 (我假设这些函数使用最少的代码输出到控制台)。

      【讨论】:

        【解决方案7】:

        不幸的是,原因是流比 printf() 慢

        你可以考虑设置一个断点,看看这些调用下面发生了什么;)

        +

        使用 cout 与 printf 的优缺点已经花费了人类十年的时间。我不想复制下面的某种冗长的讨论: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/77637c6bf362a01c?pli=1

        现实情况是 cout 比 printf 慢(如果你想让我更准确的话,我可以在这里说:一般来说)。
        是的,流旨在采用更高级别的软件设计范例并从中受益。
        是的,它们是类型安全的。
        是的,它们更灵活。
        是的,有很多非常有用的东西,比如 boost 的 lexical_cast 取决于它们。
        然而,给我尽可能多的 -1 我们你喜欢的家伙,但它仍然不会改变流比 printf 慢的事实;)

        你可能会问,为什么?
        C++ cout printing slowly
        cout or printf which of the two has a faster execution speed C++?
        mixing cout and printf for faster output

        【讨论】:

        • -1 for FUD:即使在所有情况下都是如此(事实并非如此),如果没有 1. 基准或 2. 解释原因,说库 A 比库 B 慢,是 FUD .
        • @Billy ONeal 够公平的。答案可能很简短,但它反映了现实;)无论如何感谢-1 :)
        猜你喜欢
        • 1970-01-01
        • 2014-01-04
        • 2021-05-23
        • 1970-01-01
        • 2010-09-07
        • 1970-01-01
        • 2011-04-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多