给定2个函数,哪个应该更快,如果有任何差异?假设输入数据非常大
void iterate1(const char* pIn, int Size)
{
for ( int offset = 0; offset < Size; ++offset )
{
doSomething( pIn[offset] );
}
}
Run Code Online (Sandbox Code Playgroud)
VS
void iterate2(const char* pIn, int Size)
{
const char* pEnd = pIn+Size;
while(pIn != pEnd)
{
doSomething( *pIn++ );
}
}
Run Code Online (Sandbox Code Playgroud)
两种方法都有其他问题需要考虑吗?
Boojum是正确的 - 如果你的编译器有一个很好的优化器并且启用了它.如果情况并非如此,或者您对数组的使用不是顺序的并且易于优化,那么使用数组偏移可能会慢得多.
这是一个例子.大约在1988年,我们在Mac II上实现了一个带有简单电传接口的窗口.这由24行80个字符组成.当您从自动收报机中获得新线路时,您向上滚动前23行,并在底部显示新线路.当电传打字机上有某些东西时,它不是所有时间,它以300波特率进入,其中串行协议开销大约为每秒30个字符.所以我们根本不会谈论应该对16 MHz 68020征税的事情!
但写这篇文章的人就是这样的:
char screen[24][80];
Run Code Online (Sandbox Code Playgroud)
并使用二维数组偏移来滚动字符,如下所示:
int i, j;
for (i = 0; i < 23; i++)
for (j = 0; j < 80; j++)
screen[i][j] = screen[i+1][j];
Run Code Online (Sandbox Code Playgroud)
像这样的六个窗户让机器跪了下来!
为什么?因为编译器在那些日子里是愚蠢的,所以在机器语言中,内部循环赋值的每个实例screen[i][j] = screen[i+1][j]看起来都像这样(Ax和Dx是CPU寄存器);
Fetch the base address of screen from memory into the A1 register
Fetch i from stack memory into the D1 register
Multiply D1 by a constant 80
Fetch j from stack memory and add it to D1
Add D1 to A1
Fetch the base address of screen from memory into the A2 register
Fetch i from stack memory into the D1 register
Add 1 to D1
Multiply D1 by a constant 80
Fetch j from stack memory and add it to D1
Add D1 to A2
Fetch the value from the memory address pointed to by A2 into D1
Store the value in D1 into the memory address pointed to by A1
Run Code Online (Sandbox Code Playgroud)
因此,对于23x80 = 1840内循环迭代中的每一个,我们正在讨论13种机器语言指令,总共23920条指令,包括3680个CPU密集型整数乘法.
我们对C源代码做了一些更改,所以它看起来像这样:
int i, j;
register char *a, *b;
for (i = 0; i < 22; i++)
{
a = screen[i];
b = screen[i+1];
for (j = 0; j < 80; j++)
*a++ = *b++;
}
Run Code Online (Sandbox Code Playgroud)
仍然有两个机器语言的乘法,但它们在外循环中,因此只有46个整数乘法而不是3680.而内循环*a++ = *b++语句只包含两个机器语言操作.
Fetch the value from the memory address pointed to by A2 into D1, and post-increment A2
Store the value in D1 into the memory address pointed to by A1, and post-increment A1.
Run Code Online (Sandbox Code Playgroud)
鉴于有1840个内循环迭代,总共有3680个CPU廉价指令 - 少了6.5倍 - 并且没有整数乘法.在此之后,我们从来没有足够的力量让机器陷入困境,而不是在六个电传打字窗口死亡 - 我们首先耗尽了电传打字机数据源.还有一些方法可以进一步优化这一点.
现在,现代编译器将为您做这种优化 - 如果您要求他们这样做,并且如果您的代码以允许它的方式构建.
但是仍然存在编译器无法为您执行此操作的情况 - 例如,如果您在阵列中执行非顺序操作.
所以我发现尽可能使用指针代替数组引用对我很有用.性能肯定不会更糟,而且往往更好,更好.