案例I
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))
{
}
}
}
案例II
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和II的嵌套循环之外或之内声明。哪一个在性能方面更好?为什么呢?
答案 0 :(得分:2)
该标准对绩效的评价很少,但有一条明确的规则,即优化不得改变可观察到的副作用。
标准没有描述堆栈或堆使用情况,因此编译器在使用之前的任何时刻为堆栈上的变量分配空间是完全合法的。
但最佳将取决于各种因素。在最常见的体系结构中,最有意义的是在2个位置进行所有堆栈指针调整 - 进入和退出。在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 generates three identical pieces of assembly:
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
答案 1 :(得分:0)
许多与绩效相关的问题的一般答案是“衡量并亲眼看看”。如果这很容易,那就去做吧。在这种情况下, 很容易。
有时,查看汇编代码是件好事 - 如果代码在两种情况下相同(我猜它是相同的),你甚至不需要测量它的性能。