C++ 就百分比而言,这两种方法的平均性能有多大差异?
当我试图理解标准库的实现时,我有一个问题 给定C++ 就百分比而言,这两种方法的平均性能有多大差异?,c++,optimization,hardware,C++,Optimization,Hardware,当我试图理解标准库的实现时,我有一个问题 给定 std::vector<int> myVec = { ... }; // some vector of ints std::vector myVec={…};//整数的一些向量 以下哪项平均速度更快,速度快多少,为什么 (一) for(inti(0),j(myVec.size());i
std::vector<int> myVec = { ... }; // some vector of ints
std::vector myVec={…};//整数的一些向量
以下哪项平均速度更快,速度快多少,为什么
(一)
for(inti(0),j(myVec.size());i
当递增迭代器时,只需递增指针
对具有索引的元素的访问包括对类型大小的索引乘法,以便计算指针。好吧,让我们看看
第一个循环:调用size
成员函数,在std::vector
对象上调用N次operator[]
,在这个问题中调用N次operator太多依赖项和未知项
在第一种情况下,调用函数来访问元素。可以对函数进行优化,以消除函数调用的开销,并归结为乘法和加法运算
第二种情况涉及取消对访问内存的指针的引用
这里的问题之一是处理器的能力。许多现代处理器都具有从内存中获取值的能力,可以通过解除隔离(使用零索引)或使用单个指令从指针索引
另一个影响是向量是否适合处理器的缓存线(如果它有数据缓存)。缓存线之外的任何数据都需要额外的处理逻辑
如果一种方法比另一种方法快,则可以忽略不计,除非执行1E+10次迭代。差异通常以纳秒为单位。您的程序将浪费更多时间被操作系统调出、调用函数或执行I/O。例如:差异为10ns。您的程序等待用户输入值0.5秒。每次迭代10纳秒的增益浪费在等待用户输入上
通常,此类微优化仅对高性能应用程序或必须满足关键期限的应用程序至关重要。例如,如果嵌入式系统必须每毫秒读取一个传感器,那么读取传感器花费的时间越少,系统其余部分执行的时间就越多
编辑1:
像这样的微观优化也取决于数据来自何处。内存离处理器内核越远,获取速度越慢。例如,从同一块硅上的内存中获取数据要比从位于子板上的闪存设备中访问数据快。为什么不测量它们呢?我对它们不同实现背后的理论很感兴趣。我想知道在硬件层面上发生了什么不同。考虑到两者都在编写std::cout
,根本不可能测量任何差异。但是您可能想使用的是(auto i:myVec)的,您可以使用优化吗?对于这两种使用高级优化的情况,汇编语言都是什么样子的?抱歉,但不完全正确。有些处理器具有从指针值或寄存器进行索引的指令。还取决于数据项的大小。
for (int i(0), j(myVec.size()); i < j; ++i) std::cout << myVec[i];
for (std::vector<int>::iterator i(myVec.begin()), j(myVec.end()); i != j; ++i) std::cout << *it;
Dump of assembler code for function main():
5 {
0x0000000000400880 <+0>: push %r12
0x000000000040088d <+13>: push %rbp
0x000000000040088e <+14>: push %rbx
6 std::vector<int> myVec = { 1, 2, 3, 5, 6, 7 }; // some vector of ints
7
8 for (int i(0), j(myVec.size()); i < j; ++i) std::cout << myVec[i];
0x0000000000400887 <+7>: mov $0x6,%r12d
0x000000000040088f <+15>: xor %ebx,%ebx
0x00000000004008c0 <+64>: mov 0x0(%rbp,%rbx,4),%esi
0x00000000004008c4 <+68>: mov $0x601080,%edi
0x00000000004008c9 <+73>: callq 0x4007d0 <_ZNSolsEi@plt>
0x00000000004008ce <+78>: add $0x1,%rbx
0x00000000004008d2 <+82>: cmp %ebx,%r12d
0x00000000004008d5 <+85>: jg 0x4008c0 <main()+64>
9
10 std::cout << std::endl;
11
12 for (std::vector<int>::iterator it(myVec.begin()), j(myVec.end()); it != j; ++it) std::cout << *it;
0x00000000004008f0 <+112>: mov (%rbx),%esi
0x00000000004008f2 <+114>: mov $0x601080,%edi
0x00000000004008f7 <+119>: callq 0x4007d0 <_ZNSolsEi@plt>
0x00000000004008fc <+124>: add $0x4,%rbx
0x0000000000400900 <+128>: cmp %r12,%rbx
0x0000000000400903 <+131>: jne 0x4008f0 <main()+112>
13
14 std::cout << std::endl;
15 }
0x000000000040091c <+156>: pop %rbx
0x000000000040091d <+157>: pop %rbp
0x000000000040091e <+158>: xor %eax,%eax
0x0000000000400920 <+160>: pop %r12
0x0000000000400922 <+162>: retq