嵌套循环内外变量声明的性能比较
Performance comparison between variable declaration within or outside nested loop
大小写
while (!channels_.empty())
{
for (auto it = channels_.begin(); it != channels_.end(); ++it)
{
time_t stop_time;
if (it->second->active_playlist()->status_stop_time(it->second->on_air_row(), stop_time))
{
}
}
}
案例二世
while (!channels_.empty())
{
time_t stop_time;
for (auto it = channels_.begin(); it != channels_.end(); ++it)
{
if (it->second->active_playlist()->status_stop_time(it->second->on_air_row(), stop_time))
{
}
}
}
变量stop_time在Case I和Case II的嵌套循环外部或内部声明。哪一个在性能方面更好?为什么?
该标准对性能的要求很少,但有一个明确的规则,即优化不能改变可观察到的副作用。
标准没有描述堆栈或堆的使用情况,因此编译器在使用变量之前的任何时候为堆栈上的变量分配空间都是完全合法的。
但最优取决于多种因素。在最常见的体系结构中,在两个地方(入口和出口)进行所有堆栈指针调整是最有意义的。在x86上,将堆栈指针更改640而不是在8上,没有成本差异。
此外,如果编译器可以确定值不会改变,那么优化器也可以将赋值提升到循环之外。
在实践中,基于x86和arm平台上的主流编译器(gcc, clang, msvc)将堆栈分配聚合为单个上下分配,并在给定足够的优化器设置/参数的情况下提升循环不变量。
如果有疑问,请检查组装或基准。
我们可以用godbolt来快速演示:
#include <vector>
struct Channel
{
void test(int&);
};
std::vector<Channel> channels;
void test1()
{
while (!channels.empty())
{
for (auto&& channel : channels)
{
int stop_time;
channel.test(stop_time);
}
}
}
void test2()
{
while (!channels.empty())
{
int stop_time;
for (auto&& channel : channels)
{
channel.test(stop_time);
}
}
}
void test3()
{
int stop_time;
while (!channels.empty())
{
for (auto&& channel : channels)
{
channel.test(stop_time);
}
}
}
在GCC 5.1和-O3中,这会生成三个相同的程序集:
test1():
pushq %rbp
pushq %rbx
subq $24, %rsp
.L8:
movq channels+8(%rip), %rbp
movq channels(%rip), %rbx
cmpq %rbp, %rbx
je .L10
.L7:
leaq 12(%rsp), %rsi
movq %rbx, %rdi
addq $1, %rbx
call Channel::test(int&)
cmpq %rbx, %rbp
jne .L7
jmp .L8
.L10:
addq $24, %rsp
popq %rbx
popq %rbp
ret
test2():
pushq %rbp
pushq %rbx
subq $24, %rsp
.L22:
movq channels+8(%rip), %rbp
movq channels(%rip), %rbx
cmpq %rbp, %rbx
je .L20
.L14:
leaq 12(%rsp), %rsi
movq %rbx, %rdi
addq $1, %rbx
call Channel::test(int&)
cmpq %rbx, %rbp
jne .L14
jmp .L22
.L20:
addq $24, %rsp
popq %rbx
popq %rbp
ret
test3():
pushq %rbp
pushq %rbx
subq $24, %rsp
.L26:
movq channels+8(%rip), %rbp
movq channels(%rip), %rbx
cmpq %rbp, %rbx
je .L28
.L25:
leaq 12(%rsp), %rsi
movq %rbx, %rdi
addq $1, %rbx
call Channel::test(int&)
cmpq %rbx, %rbp
jne .L25
jmp .L26
.L28:
addq $24, %rsp
popq %rbx
popq %rbp
ret
对于许多与性能相关的问题,一般的答案是"自己衡量一下"。如果很容易,就去做。在这种情况下,是简单。
有时候,看看汇编代码是很好的——如果代码在你的两种情况下是相同的(我猜是),你甚至不需要衡量它的性能。
相关文章:
- 为什么constexpr的性能比正常表达式差
- 在现代C++中,侵入式容器是否仍然比非侵入式容器具有性能优势?
- 每个编译器的C++性能,比C#慢200倍
- C++多线程性能比单线程代码慢
- 多线程功能性能比单线螺纹差
- localtime() 比 Linux 上的 gmtime() 性能问题多 24 倍
- 为什么这个普通的数组实现比STD ::向量实现性能慢
- C:pthread的性能,比单线程低
- 全局对象是否提供比多个本地实例更好的性能
- 为什么 std::make_shared<>() 的性能比 boost::make_shared() 好得多?
- 在OpenGL中为顶点、uvs和法线使用一个缓冲区是否比使用三个缓冲区性能更好
- 性能权衡-MATLAB何时比C/C++更好/更慢
- 为什么预分配的函数指针的性能比分支差
- 为什么 std::vector 比本机数组的性能更高
- C++特征库如何比专门的供应商库性能更好
- pthread_mutex锁是否提供比用户在代码中施加的内存屏障更高的性能
- c++ 11委托的函数是否比c++ 03调用init函数的函数性能差?
- 放炮的性能比先放炮后复核的性能差
- 为什么我的散点代码的性能比Vc SIMD更好
- 为什么 C++ fseek/fread 的性能比 C# FileStream 的 Seek/Read 高几倍