关于循环速度的问题

发布于 2024-09-12 06:07:35 字数 599 浏览 8 评论 0原文

我有以下两个循环:

#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;
int main(){

    int start=clock();
    for (int i=0;i<100;i++)
        cout<<i<<" "<<endl;
    cout<<clock()-start<<"\n"<<endl;
    cout<<"\n";

    int start1=clock();
    for (int j=0;j<100;++j)
        cout<<j<<" "<<endl;
    cout<<"\n";
    cout<<clock()-start1<<" \n "<<endl;

    return 0;
}

我运行了三次。在前两次运行中,第二个循环最快,但在第三次运行中,第一个循环最快。这意味着什么?哪个更好?这要看具体情况吗?

I have the following two loops:

#include <iostream>
#include <stdlib.h>
#include <time.h>

using namespace std;
int main(){

    int start=clock();
    for (int i=0;i<100;i++)
        cout<<i<<" "<<endl;
    cout<<clock()-start<<"\n"<<endl;
    cout<<"\n";

    int start1=clock();
    for (int j=0;j<100;++j)
        cout<<j<<" "<<endl;
    cout<<"\n";
    cout<<clock()-start1<<" \n "<<endl;

    return 0;
}

I ran that three times. On the first two runs, the second loop was fastest but, on the third run, the first loop was fastest. What does this mean? Which is better? Does it depend on the situation?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

林空鹿饮溪 2024-09-19 06:07:35

循环的运行时间绝大多数由输入输出操作决定。这意味着您观察到的时间 1) 与循环的实际性能无关(即 i++++j),2) 几乎不可预测,并且不稳定(本质上是随机的)。

换句话说,你的实验毫无意义。这绝对没有任何意义。

最后,在不使用内置++运算符结果的情况下,后缀和前缀增量之间绝对没有区别。在任何合理的编译器中,两个循环都将具有完全相同的性能。

The running time of your loops is overwhelmingly dominated by input-output operations. This means that the time you observe 1) has nothing to do with the actual performance of the loop (i.e. i++ vs ++j), 2) is pretty much unpredictable and unstable (essentially random).

In other words, your experiment is meaningless. It means absolutely nothing.

Finally, in situations when the result of the built-in ++ operator is not used, there is absolutely no difference between postfix and prefix increment. In any reasonable compiler both of your loops will have absolutely identical performance.

小ぇ时光︴ 2024-09-19 06:07:35

在您的情况下,这可能是标准测量误差,使用后增量或前增量并不重要。对于标准类型(int、byte ...)来说这并不重要。

但是您应该习惯使用预自增,因为如果您在类上使用它们,则会产生性能影响,具体取决于这些运算符的实现方式。后自增运算符 i++ 必须复制对象

例如:

class integer
{
public:
  integer(int t_value)
    : m_value(t_value)
  {
  }

  int get_value() { return m_value; }

  integer &operator++() // pre increment operator
  {
    ++m_value;
    return *this;
  }

  integer operator++(int) // post increment operator
  {
    integer old = *this; // a copy is made, it's cheap, but it's still a copy
    ++m_value;
    return old; // Return old copy
  }

private:
  int m_value;

看看下面的答案

StackOverflow:i++ 比 ++i 效率低,如何显示?

In your case it is probably standard measurement error and it does not matter do you use post-increment or pre-increment. For standard types (int, byte ...) it does not matter.

BUT you should get used to using pre-increment because there are performance implications if you are using them on a Class, depending how those operators are implemented. Post-increment operator i++ has to make a copy of the object

For example:

class integer
{
public:
  integer(int t_value)
    : m_value(t_value)
  {
  }

  int get_value() { return m_value; }

  integer &operator++() // pre increment operator
  {
    ++m_value;
    return *this;
  }

  integer operator++(int) // post increment operator
  {
    integer old = *this; // a copy is made, it's cheap, but it's still a copy
    ++m_value;
    return old; // Return old copy
  }

private:
  int m_value;

Take a look at the following answer

StackOverflow: i++ less efficient than ++i, how to show this?

风吹雨成花 2024-09-19 06:07:35

这些循环对于 int 类型的归纳变量是等效的。增量后与增量前的问题已在此多次得到解答。尝试稍微搜索一下档案。

此外,与标准 IO 相比,增量操作只需要一小部分时间。您的测试是测量 IO 的速度而不是增量操作的速度。

These loops are equivalent for induction variable of int type. The post increment versus pre increment questions has been answered here several times. Try to search the archives a little.

Also, the increment operation takes only a small fraction of time compared to the standard IO. Your test is measuring speed of the IO rather than speed of the increment operations.

久夏青 2024-09-19 06:07:35

旧的 GCC 3.4.4 是这样做的:

第一个循环:

.L11:
        cmpl    $99, -8(%ebp)
        jg      .L12
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -8(%ebp)
        pushl   $_ZSt4cout
.LCFI7:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI8:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -8(%ebp), %eax
        incl    (%eax)
        jmp     .L11
.L12:

第二个循环:

.L14:
        cmpl    $99, -12(%ebp)
        jg      .L15
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -12(%ebp)
        pushl   $_ZSt4cout
.LCFI13:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI14:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -12(%ebp), %eax
        incl    (%eax)
        jmp     .L14
.L15:

你能发现任何差异吗? :)(除了 i 和 j 位于堆栈上的不同位置 -8(%ebp) 和 -12(%ebp) 之外)

Old GCC 3.4.4 does this:

First loop:

.L11:
        cmpl    $99, -8(%ebp)
        jg      .L12
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -8(%ebp)
        pushl   $_ZSt4cout
.LCFI7:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI8:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -8(%ebp), %eax
        incl    (%eax)
        jmp     .L11
.L12:

Second loop:

.L14:
        cmpl    $99, -12(%ebp)
        jg      .L15
        subl    $8, %esp
        pushl   $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
        subl    $12, %esp
        pushl   $.LC0
        subl    $12, %esp
        pushl   -12(%ebp)
        pushl   $_ZSt4cout
.LCFI13:
        call    _ZNSolsEi
        addl    $20, %esp
        pushl   %eax
        call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
        addl    $20, %esp
        pushl   %eax
.LCFI14:
        call    _ZNSolsEPFRSoS_E
        addl    $16, %esp
        leal    -12(%ebp), %eax
        incl    (%eax)
        jmp     .L14
.L15:

Can you find any differences? :) (besides i and j being on different locations on stack -8(%ebp) and -12(%ebp))

踏雪无痕 2024-09-19 06:07:35

这意味着您应该使用统计技术来确定哪个循环更快(我希望这些技术能够证明它们彼此相当)。

知道您的CPU 在您放置的负载之外正在做什么。

它可能会启动计划任务、处理中断以及各种会影响结果的事情。

您可能必须进行一百万次运行,扔掉异常值,并对其余的进行平均才能获得像样的样本。

最重要的是,一百次迭代并不算多,特别是因为您正在对 cout 进行函数调用,这很可能会占用循环控制所花费的时间。

当我在 UNIX 下运行检查时,出于这个原因,我使用经过时间。系统和用户时间给出给定进程使用 CPU 的秒数,无论经过的时间如何。

It means you should use statistical techniques to work out which loop is faster (and I would hope those techniques established that they were pretty much on par with each other).

You have no idea what your CPU is doing over and above the load you're putting it under here.

It could be starting up scheduled tasks, handling interrupts, all sorts of things that would skew your results.

You may well have to do a million runs, toss out the outliers, and average the rest to get a decent sample.

On top of that, a hundred iterations is not much, especially since you're doing function calls to cout which may well swamp the time spent doing the loop control.

When I run checks under UNIX, I don't use elapsed time for this very reason. The system and user time give how many seconds the CPU was in use for the given process regardless of the elapsed time.

两个我 2024-09-19 06:07:35

++i 应该产生与 i++ 相同的机器代码,并且在任何半途而废的编译器上都具有未使用的结果(前提是它没有以奇特的方式重载,而 int 则不然)。即使没有(你需要从上个世纪挖出一个非常愚蠢的编译器),差异也很小,你永远不必担心它。好吧,在某些情况下,您确实需要榨取每一点性能,但我们中至少有人会遇到这种情况。即便如此,循环体也具有更大的优化潜力(即使在您过于简化的示例中 - I/O 比复制机器字的成本要高得多)。

还是一句话:过早的优化是万恶之源。

++i should result in the same machine code as i++ with unused result on any halfway-decent compiler (provided it's not overloaded in a fancy way, which can't be the case for int). And even if it doesn't (you'd need to dig out a pretty stupid compiler from the last century), the difference is so small you should never have to worry about it. Well, there are cases where you do need to squeeze every tiny bit of performance out of it, but the least of us every get into this situation. And even then, the body of the loop has way more optimization potential (even in your oversimplified example - I/O is way more costy than copying a machine word).

Or in one sentence: Premature optimization is the root of all evil.

笙痞 2024-09-19 06:07:35

据我所知,循环中的唯一区别是循环变量的前/后增量。大部分处理时间将花费在 cout 上。相比之下,增量的时间可以忽略不计。

From what I see, the only difference in the loops is the pre / post increment of the loop variable. The bulk of the process time will be spent on the cout. Incrementing will be of negligible time in comparison.

巡山小妖精 2024-09-19 06:07:35

++i 是预增
i++ 是后增量,

请参阅 Operator 了解详细信息

++i is preincrement
i++ is postincrement

see Operator for details

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文