11

我正在尝试重复一段代码,而不使用条件,但仍然只重复特定次数。

基本上,是这样的:

repeat(50)
{
    //Do stuff here.
}

有没有办法做到这一点?除了复制和粘贴 50 次?

我这样做是因为我想如果我知道我想重复多少次,它会比每次检查一个条件更快。那准确吗?还是我还要检查它被重复了多少次?

基本上,它会更快吗?

4

5 回答 5

18

您尝试通过使用某种构造(包括手动剪切和粘贴代码)来优化循环的执行速度来优化循环是不明智的。不要这样做;相反,它可能会“取消优化”执行速度。

在我遇到过的任何 C++ 实现(MSVC 6.0、2003、2005、2010、GCC 各种版本、Diab 各种版本)中,绝对为零,抱歉我没有强调足够,零,分配循环所涉及的时间计数变量,假设为分配循环计数变量的函数分配了任何其他变量。对于一个不进行函数调用的简单循环,循环计数变量甚至可能永远不会进入内存;它可能在其整个生命周期内完全保存在单个 CPU 寄存器中。即使它存储在内存中,它也会在运行时堆栈上,并且它的空间(以及任何其他局部变量)将在单个操作中一次全部占用,这取决于分配在栈上的变量。

堆栈上的循环计数器变量分配示例:

for (int i=0; i<50; ++i) {
    ....
}

堆栈上的另一个示例循环计数器变量分配:

int i = 0;
for (; i<50; ++i) {
    ....
}

在堆上分配的示例循环计数器变量(不要这样做;这很愚蠢):

int* ip = new int;
for (*ip=0; *ip<50; ++(*ip)) {
    ....
}
delete ip;

现在解决尝试通过手动复制和粘贴而不是使用循环和计数器来优化循环的问题:

您正在考虑做的是手动形式的循环展开。循环展开是编译器有时用于减少循环中涉及的开销的优化。只有在编译时可以知道循环的迭代次数(即迭代次数是一个常数,即使该常数涉及基于其他常数的计算),编译器才能做到这一点。在某些情况下,编译器可能会确定值得展开循环,但通常不会完全展开循环。例如,在您的示例中,编译器可能会确定将循环从 50 次迭代展开到仅具有 5 个循环体副本的 10 次迭代将具有速度优势。循环变量仍然存在,但不是对循环计数器进行 50 次比较,现在代码只需进行 10 次比较。这是一个折衷方案,因为循环体的 5 个副本在缓存中占用了 5 倍的空间,这意味着加载相同指令的这些额外副本会强制缓存驱逐(丢弃)已经存在的许多指令缓存并且您可能希望保留在缓存中。此外,从主内存加载这 4 个额外的循环体指令副本比在循环根本没有展开的情况下简单地从缓存中抓取已经加载的指令要花费更多时间。这意味着加载相同指令的这些额外副本会强制缓存驱逐(丢弃)已经在缓存中并且您可能希望保留在缓存中的许多指令。此外,从主内存加载这 4 个额外的循环体指令副本比在循环根本没有展开的情况下简单地从缓存中抓取已经加载的指令要花费更多时间。这意味着加载相同指令的这些额外副本会强制缓存驱逐(丢弃)已经在缓存中并且您可能希望保留在缓存中的许多指令。此外,从主内存加载这 4 个额外的循环体指令副本比在循环根本没有展开的情况下简单地从缓存中抓取已经加载的指令要花费更多时间。

所以总而言之,只使用循环体的一个副本并继续并保留循环逻辑通常更有利。(即根本不做任何循环展开。)

于 2013-04-29T16:23:06.127 回答
3

完全有可能将 arepeat(x)作为语言的一部分,但由于某种原因没有这样的东西 - C 和 C++ 的设计在某种程度上遵循处理器可以做的事情,而且我不熟悉单个处理器(我使用过大约 10 种不同的处理器架构)可以执行“循环这么多次”而无需某种“检查我们是否达到数字”。

所以,你将不得不编写一些代码来检查你重复了多少次(或者,还有多少次要做 - 有一个名为“循环”的 x86 指令可以做到这一点 - 倒计时,如果计数器不为零,跳转到循环的开头)。

如果编译器希望“展开”一个循环,因为它具有恒定的迭代次数,并且它决定“展开这个更快”[编译器总是决定这类事情,并且经常做对],那么编译器可能会这样做。但是您仍然必须编写“检查”的代码。

于 2013-04-28T22:58:50.350 回答
3

如果您想要能够编写的语法精度,repeat(x) {}那么您可以使用宏。

就像是:

#include <iostream>

#define repeat(x) for(int i = x; i--;)

int main()
{
    repeat(10) 
    {
        std::cout << i << std::endl;
    }

    return 0;
}

这里的实现还在 for 循环中使用了与零的比较,而不是小于运算符,这可能会稍微快一些

于 2020-01-16T11:56:25.867 回答
0

这个怎么样:

typedef std::vector<int> times;
for (auto count : times(5))
{
    // execute the loop 5 times
}
于 2020-05-04T07:51:31.100 回答
-3

我不得不说,速度的最大提升将是您没有分配迭代变量,但您要求的内容不可避免地需要检查条件。本质上,您所拥有的如下。

int i = 0;
for(; i< 50; i++)
{
    Do Something.
}

我将 I 移到 for 循环之外的原因是声明它可以是在循环之前初始化的任何变量。它与以下内容完全相同,

for(int i =0; i< 50; i++)
{
}
于 2013-04-28T22:51:31.317 回答