排序数组对程序运行的影响
来源:互联网 发布:新疆移动4g网络什么时候开通 编辑:程序博客网 时间:2024/05/16 11:27
问题:使用排序过的数组,比未排序的数组运行速度要快。作为有探究精神的你,肯定要问为什么?第一反应,它应该和存储有关,当排序后数组被连续的存储在一块连续的内存(应该是内存还是地址块更恰当呢?)中,如图:
那么最后造成速度快慢的原因,应该源自于两种存储方式下,对数据访问的不同所造成。
接下来,老规矩,上代码测试。
#include <algorithm>#include <ctime>#include <iostream>int main(){ // Generate data const unsigned arraySize = 32768; int data[arraySize]; for (unsigned c = 0; c < arraySize; ++c) data[c] = std::rand() % 256; // !!! With this, the next loop runs faster std::sort(data, data + arraySize); clock_t start = clock(); long long sum = 0; for (unsigned i = 0; i < 100000; ++i) { // Primary loop for (unsigned c = 0; c < arraySize; ++c) { if (data[c] >= 128) sum += data[c]; } } double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC; std::cout << elapsedTime << std::endl; std::cout << "sum = " << sum << std::endl;}
gcc编译后得到结果,排序后的情况:
未排序的情况:,时间上差了很多。当然了,这只能说明在数据量相当大的情况下,排序对性能有影响。再来测试一个数据量比较小的情况,将代码改为
#include <algorithm>#include <ctime>#include <iostream>int main(){ // Generate data const unsigned arraySize = 32; int data[arraySize]; for (unsigned c = 0; c < arraySize; ++c) data[c] = std::rand() % 12; // !!! With this, the next loop runs faster std::sort(data, data + arraySize); clock_t start = clock(); long long sum = 0; for (unsigned i = 0; i < 100; ++i) { // Primary loop for (unsigned c = 0; c < arraySize; ++c) { if (data[c] >= 6) sum += data[c]; } } double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC; std::cout << elapsedTime << std::endl; std::cout << "sum = " << sum << std::endl;}
排序--> 未排序-->。
在数据量很小的情况下,两者并没有太大的差别。为了提高程序的性能,我们可以适当的使用sort()来优化。
回到主题,将test.cpp编译成汇编代码
LBB0_1: ## => 对应操作 for (unsigned c = 0; c < arraySize; ++c)callq_rand ## => data[c] = std::rand() % 256;movl%eax, %ecxsarl$31, %ecxshrl$24, %ecxaddl%eax, %ecxandl$-256, %ecxsubl%ecx, %eaxmovl%eax, -131120(%rbp,%rbx,4)incq%rbxcmpq$32768, %rbxjneLBB0_1## BB#2: ## => std::sort(data, data + arraySize);leaq-48(%rbp), %rsi ## => clock_t start = clock();leaq-131120(%rbp), %rdileaq-131136(%rbp), %rdxcallq__ZNSt3__16__sortIRNS_6__lessIiiEEPiEEvT0_S5_T_xorl%ebx, %ebxcallq_clockmovq%rax, %r14movdqaLCPI0_0(%rip), %xmm8movdqaLCPI0_1(%rip), %xmm9pxor%xmm8, %xmm9xorl%r13d, %r13d.align4, 0x90LBB0_3: ## %overflow.checked ## =>This Loop Header: Depth=1 ## Child Loop BB0_4 Depth 2movd%r13, %xmm3pxor%xmm2, %xmm2xorl%eax, %eax.align4, 0x90LBB0_4: ## %vector.body ## Parent Loop BB0_3 Depth=1 ## => 内循环:for (unsigned c = 0; c < arraySize; ++c) ## { ## if (data[c] >= 128) ## sum += data[c]; ## }movslq-131116(%rbp,%rax,4), %rcxmovd%rcx, %xmm5movslq-131120(%rbp,%rax,4), %rcxmovd%rcx, %xmm4punpcklqdq%xmm5, %xmm4movslq-131108(%rbp,%rax,4), %rcxmovd%rcx, %xmm6movslq-131112(%rbp,%rax,4), %rcxmovd%rcx, %xmm5punpcklqdq%xmm6, %xmm5movdqa%xmm4, %xmm6pxor%xmm8, %xmm6movdqa%xmm6, %xmm7pcmpgtd%xmm9, %xmm7pshufd$160, %xmm7, %xmm0pcmpeqd%xmm9, %xmm6pshufd$245, %xmm6, %xmm6pand%xmm0, %xmm6pshufd$245, %xmm7, %xmm0por%xmm6, %xmm0movdqa%xmm5, %xmm6pxor%xmm8, %xmm6movdqa%xmm6, %xmm7pcmpgtd%xmm9, %xmm7pshufd$160, %xmm7, %xmm1pcmpeqd%xmm9, %xmm6pshufd$245, %xmm6, %xmm6pand%xmm1, %xmm6pshufd$245, %xmm7, %xmm1por%xmm6, %xmm1paddq%xmm3, %xmm4paddq%xmm2, %xmm5pand%xmm0, %xmm4pandn%xmm3, %xmm0movdqa%xmm0, %xmm3por%xmm4, %xmm3pand%xmm1, %xmm5pandn%xmm2, %xmm1movdqa%xmm1, %xmm2por%xmm5, %xmm2addq$4, %raxcmpq$32768, %rax ## imm = 0x8000jneLBB0_4## BB#5: ## %middle.block ## 外部循环:for (unsigned i = 0; i < 100000; ++i)paddq%xmm3, %xmm2pshufd$78, %xmm2, %xmm0paddq%xmm2, %xmm0movd%xmm0, %r13incl%ebxcmpl$100000, %ebxjneLBB0_3## BB#6: static_cast<double>(clock() - start) / CLOCKS_PER_SEC;callq_clocksubq%r14, %raxmovd%rax, %xmm0punpckldqLCPI0_2(%rip), %xmm0 ## xmm0 = xmm0[0],mem[0],xmm0[1],mem[1]subpdLCPI0_3(%rip), %xmm0haddpd%xmm0, %xmm0divsdLCPI0_4(%rip), %xmm0movq__ZNSt3__14coutE@GOTPCREL(%rip), %rdicallq__ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEElsEdmovq%rax, %r14movq(%r14), %raxmovq-24(%rax), %rsiaddq%r14, %rsileaq-131136(%rbp), %r15movq%r15, %rdicallq__ZNKSt3__18ios_base6getlocEv
发现从汇编代码,并不能看出什么,两者完全一样。那么这个问题就不是汇编层级的优化导致的。然后在查找了一些资料后发现,是CPU流水指令有一个分支预测技术。
代码中内循环里有一个条件判断。每一次CPU执行这个条件判断时,CPU都可能跳转到循环开始处的指令,即不执行if后的指令。使用分支预测技术,当处理已经排序的数组时,在若干次data[c]>=128都不成立时(或第一次不成立时,取决于分支预测的实现),CPU预测这个分支是始终会跳转到循环开始的指令时,这个时候CPU将保持有效的执行,不需要重新等待到新的地址取指;同样,当data[c]>=128条件成立若干次后,CPU也可以预测这个分支是不必跳转的,那么这个时候CPU也可以保持高效执行。
相反,如果是无序的数组,CPU的分支预测在很大程度上都无法预测成功,基本就是50%的预测成功概率,这将消耗大量的时间,因为CPU很多时间都会等待取指单元重新取指。
- 排序数组对程序运行的影响
- static对程序运行影响
- 代码局部性对程序运行速度的影响
- 索引对排序的影响
- 浏览器对程序的影响
- 编写Linux内核程序查看优先级对程序运行的影响
- RMI Spy对程序运行产生的影响(Eclipse 的RMI插件)
- oracle中 rownum 对排序的影响
- Java重排序对多线程的影响
- 影响Java程序运行的几个问题
- 编写对数组进行排序的程序,要求用…
- 数据库视图对程序的影响
- SQL对程序性能的影响
- SQL对程序性能的影响
- 程序规模对构建的影响
- android sharedUserId对程序升级的影响
- Fraps 对D3D程序的影响
- 调用外部程序对输入的影响
- ThinkPhp3.2.3 多项目 后台 APP接口设计 框架设计
- 帝国cms中的关于对附件乱码,随机数码问题的修改
- android intent 选择文件
- ViewPager-IconPageIndicator导航栏效果(增加点击切换)
- [LeetCode]:Reverse Integer(Only两类解法)
- 排序数组对程序运行的影响
- Js作用域与作用域链详解
- 软件版本: alpha, beta, release, SPx
- 原子操作的好处
- 四、创建界面
- lua中遍历table的几种方式比较
- VS一些设置及编译时候的一些问题以及解决方案
- iOS App检测版本更新
- 电商之路